Adapt welcome wallpaper to SGU gender

This commit is contained in:
2026-09-08 12:07:43 -06:00
parent 1fe2006404
commit 93871b62b0
12 changed files with 367 additions and 25 deletions
+1
View File
@@ -103,6 +103,7 @@ Bootstrap reproducible para el laboratorio SGU.
- `sgu-client-bootstrap-$Version.zip`: registra un certificado mTLS único, instala y valida el Credential Provider antes de unir el equipo al dominio, habilita RDP/WinRM y se repara al arranque.
- `sgu-linux-client-bootstrap-$Version.zip`: une clientes Debian/Ubuntu o RHEL/Fedora/Rocky/AlmaLinux con realmd, Kerberos y SSSD. Solicita interactivamente la contraseña de unión y no instala el Credential Provider de Windows.
- El Auth Broker clasifica sin tareas programadas cada cuenta autenticada: `AL` se agrega a `SGU-Alumnos`, `AD` a `SGU-Administrativos` y `DO` a `SGU-Docentes`; el bootstrap crea estos grupos de seguridad de forma idempotente.
- El enriquecimiento obtiene el sexo de los módulos SGU de personal/alumnos, lo conserva como la línea administrada `SGU-Gender: Male|Female` en Notas de AD y adapta el fondo de Windows/Linux; cuando falta utiliza redacción neutral.
- El servidor configura WEF/WEC para registrar sesiones y fallos, inventariar el estado alcanzable de las máquinas cada cinco minutos y conservar durante 183 días tanto esos eventos como el diagnóstico estructurado del Auth Broker.
- Windows Home se detecta y se rechaza con una explicación, ya que no admite unión a Active Directory ni RDP host.
+59 -6
View File
@@ -8,6 +8,8 @@ param(
[string]$ComputerName = $env:COMPUTERNAME,
[string]$Location,
[string]$OrganizationalUnit,
[ValidateSet('Male', 'Female')]
[string]$Gender,
[ValidateRange(640, 16384)]
[int]$CanvasWidth,
[ValidateRange(480, 16384)]
@@ -67,6 +69,22 @@ function Get-ImmediateOrganizationalUnit {
return $null
}
function Get-SguGenderFromInfo {
param([string]$Info)
if (-not $Info) {
return $null
}
foreach ($line in $Info -split '\r?\n') {
if ($line -match '^\s*SGU-Gender:\s*(Male|Female)\s*$') {
return [Globalization.CultureInfo]::InvariantCulture.TextInfo.ToTitleCase(
$Matches[1].ToLowerInvariant())
}
}
return $null
}
function Get-DirectoryWelcomeMetadata {
param(
[Parameter(Mandatory)][string]$UserName,
@@ -93,6 +111,7 @@ function Get-DirectoryWelcomeMetadata {
$userSearcher.Filter = '(&(objectCategory=person)(objectClass=user)(sAMAccountName={0}))' -f `
(ConvertTo-LdapFilterValue -Value $UserName)
[void]$userSearcher.PropertiesToLoad.Add('displayName')
[void]$userSearcher.PropertiesToLoad.Add('info')
$userResult = $userSearcher.FindOne()
$directoryDisplayName = if ($userResult -and $userResult.Properties['displayname'].Count) {
[string]$userResult.Properties['displayname'][0]
@@ -100,6 +119,12 @@ function Get-DirectoryWelcomeMetadata {
else {
$null
}
$directoryGender = if ($userResult -and $userResult.Properties['info'].Count) {
Get-SguGenderFromInfo -Info ([string]$userResult.Properties['info'][0])
}
else {
$null
}
}
finally {
$userSearcher.Dispose()
@@ -136,6 +161,7 @@ function Get-DirectoryWelcomeMetadata {
[pscustomobject]@{
DisplayName = $directoryDisplayName
Gender = $directoryGender
Location = $directoryLocation
OrganizationalUnit = Get-ImmediateOrganizationalUnit -DistinguishedName $computerDn
}
@@ -156,11 +182,20 @@ function Get-SpanishArticle {
function Get-WelcomeLocationText {
param(
[string]$Room,
[string]$OuName
[string]$OuName,
[string]$Gender
)
$located = 'Est{0}s ubicado en' -f [char]0x00E1
$engineeringLab = 'Bienvenido al Laboratorio de C{0}mputo de Ingenier{1}a.' -f [char]0x00F3,[char]0x00ED
$located = switch ($Gender) {
'Male' { 'Est{0}s ubicado en' -f [char]0x00E1 }
'Female' { 'Est{0}s ubicada en' -f [char]0x00E1 }
default { 'Ubicaci{0}n:' -f [char]0x00F3 }
}
$engineeringLab = switch ($Gender) {
'Male' { 'Bienvenido al Laboratorio de C{0}mputo de Ingenier{1}a.' -f [char]0x00F3,[char]0x00ED }
'Female' { 'Bienvenida al Laboratorio de C{0}mputo de Ingenier{1}a.' -f [char]0x00F3,[char]0x00ED }
default { 'Acceso al Laboratorio de C{0}mputo de Ingenier{1}a.' -f [char]0x00F3,[char]0x00ED }
}
$Room = if ($Room) { $Room.Trim() } else { $null }
$OuName = if ($OuName) { $OuName.Trim() } else { $null }
@@ -184,6 +219,16 @@ function Get-WelcomeLocationText {
return $engineeringLab
}
function Get-WelcomeHeading {
param([string]$Gender)
switch ($Gender) {
'Male' { return 'Bienvenido,' }
'Female' { return 'Bienvenida,' }
default { return 'Te damos la bienvenida,' }
}
}
function Get-AvailableFontFamily {
param(
[Parameter(Mandatory)][string[]]$Candidates,
@@ -270,10 +315,15 @@ if (-not $DisplayName) {
if (-not $PSBoundParameters.ContainsKey('Location') -and $metadata) {
$Location = $metadata.Location
}
$genderWasProvided = $PSBoundParameters.ContainsKey('Gender')
if (-not $genderWasProvided -and $metadata) {
$Gender = $metadata.Gender
}
$welcomeHeading = Get-WelcomeHeading -Gender $Gender
if (-not $PSBoundParameters.ContainsKey('OrganizationalUnit') -and $metadata) {
$OrganizationalUnit = $metadata.OrganizationalUnit
}
$locationText = Get-WelcomeLocationText -Room $Location -OuName $OrganizationalUnit
$locationText = Get-WelcomeLocationText -Room $Location -OuName $OrganizationalUnit -Gender $Gender
if (-not $CanvasWidth -or -not $CanvasHeight) {
try {
@@ -366,7 +416,7 @@ try {
$format.Trimming = [Drawing.StringTrimming]::EllipsisWord
try {
$graphics.FillRectangle($panelBrush, $panelX, $panelY, $panelWidth, $panelHeight)
Draw-CenteredText -Graphics $graphics -Text 'Bienvenido,' -Font $welcomeFont `
Draw-CenteredText -Graphics $graphics -Text $welcomeHeading -Font $welcomeFont `
-Brush $accentBrush -Bounds ([Drawing.RectangleF]::new($panelX, $panelY + 24*$scale, $panelWidth, 50*$scale)) -Format $format
Draw-CenteredText -Graphics $graphics -Text $DisplayName -Font $nameFont `
-Brush $whiteBrush -Bounds ([Drawing.RectangleF]::new($panelX + 30*$scale, $panelY + 64*$scale, $panelWidth - 60*$scale, 105*$scale)) -Format $format
@@ -433,12 +483,15 @@ namespace Sgu {
}
}
Write-WelcomeLog -Message ("OK computer={0}; location={1}; ou={2}; output={3}" -f $ComputerName,[bool]$Location,[bool]$OrganizationalUnit,$OutputPath)
$genderLogValue = if ($Gender) { $Gender } else { 'Neutral' }
Write-WelcomeLog -Message ("OK computer={0}; gender={1}; location={2}; ou={3}; output={4}" -f $ComputerName,$genderLogValue,[bool]$Location,[bool]$OrganizationalUnit,$OutputPath)
[pscustomobject]@{
DisplayName = $DisplayName
ComputerName = $ComputerName
Location = $Location
OrganizationalUnit = $OrganizationalUnit
Gender = $Gender
WelcomeHeading = $welcomeHeading
LocationText = $locationText
OutputPath = $OutputPath
Applied = -not $SkipApply
+35 -7
View File
@@ -53,6 +53,7 @@ computer_name=${computer_name^^}
location=''
distinguished_name=''
organizational_unit=''
gender=''
read_ldif_value() {
local attribute=$1
@@ -108,9 +109,18 @@ if [[ -n $DOMAIN_CONTROLLER && -n $BASE_DN ]] &&
user_result=$(ldapsearch -LLL -N -o ldif-wrap=no -Y GSSAPI \
-H "ldap://${ldap_server}" -b "$BASE_DN" \
"(&(objectCategory=person)(objectClass=user)(sAMAccountName=${account_name}))" \
displayName 2>/dev/null || true)
displayName info 2>/dev/null || true)
directory_display_name=$(read_ldif_value displayName "$user_result")
[[ -n $directory_display_name ]] && display_name=$directory_display_name
directory_info=$(read_ldif_value info "$user_result")
gender=$(printf '%s\n' "$directory_info" | awk -F: '
tolower($1) ~ /^[[:space:]]*sgu-gender[[:space:]]*$/ {
value=tolower($2); gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
if (value == "male") print "Male"
else if (value == "female") print "Female"
exit
}
')
fi
else
log_message 'WARN AD metadata query skipped because Kerberos or LDAP session data was unavailable.'
@@ -136,6 +146,24 @@ with_article() {
fi
}
case "$gender" in
Male)
welcome_text='Bienvenido,'
located_text='Estás ubicado en'
engineering_lab_text='Bienvenido al Laboratorio de Cómputo de Ingeniería.'
;;
Female)
welcome_text='Bienvenida,'
located_text='Estás ubicada en'
engineering_lab_text='Bienvenida al Laboratorio de Cómputo de Ingeniería.'
;;
*)
welcome_text='Te damos la bienvenida,'
located_text='Ubicación:'
engineering_lab_text='Acceso al Laboratorio de Cómputo de Ingeniería.'
;;
esac
if [[ -n $location && -n $organizational_unit ]]; then
room_phrase=$(with_article "$location")
ou_article=$(article_for "$organizational_unit")
@@ -146,13 +174,13 @@ if [[ -n $location && -n $organizational_unit ]]; then
else
ou_phrase="de ${organizational_unit}"
fi
location_text="Estás ubicado en ${room_phrase} ${ou_phrase}."
location_text="${located_text} ${room_phrase} ${ou_phrase}."
elif [[ -n $location ]]; then
location_text="Estás ubicado en $(with_article "$location")."
location_text="${located_text} $(with_article "$location")."
elif [[ -n $organizational_unit ]]; then
location_text="Estás ubicado en $(with_article "$organizational_unit")."
location_text="${located_text} $(with_article "$organizational_unit")."
else
location_text='Bienvenido al Laboratorio de Cómputo de Ingeniería.'
location_text=$engineering_lab_text
fi
width=1600
@@ -210,7 +238,7 @@ if ! "${image_command[@]}" "$BASE_IMAGE" \
-gravity center \
-font "$sans_font" -weight 700 -style Normal -pointsize "$welcome_size" \
-fill '#D3E2FF' -stroke 'rgba(0,0,0,0.48)' -strokewidth 1 \
-annotate "+0-$(( 92 * scale / 100 ))" 'Bienvenido,' \
-annotate "+0-$(( 92 * scale / 100 ))" "$welcome_text" \
-font "$serif_font" -weight 700 -style Italic -pointsize "$name_size" \
-fill white -annotate "+0-$(( 22 * scale / 100 ))" "$display_name" \
-font "$sans_font" -weight 400 -style Normal -pointsize "$location_size" \
@@ -242,7 +270,7 @@ if [[ $applied == false ]] && command -v xfconf-query >/dev/null 2>&1; then
fi
if [[ $applied == true ]]; then
log_message "OK computer=${computer_name}; location=$([[ -n $location ]] && printf true || printf false); ou=$([[ -n $organizational_unit ]] && printf true || printf false); output=${output_path}"
log_message "OK computer=${computer_name}; gender=${gender:-Neutral}; location=$([[ -n $location ]] && printf true || printf false); ou=$([[ -n $organizational_unit ]] && printf true || printf false); output=${output_path}"
else
log_message 'WARN Wallpaper rendered, but no supported desktop background API was found.'
fi