Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b510082d4 |
@@ -593,7 +593,8 @@ finally {
|
|||||||
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $priorTrustedHosts -Force
|
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $priorTrustedHosts -Force
|
||||||
}
|
}
|
||||||
if (-not $winRmWasRunning) {
|
if (-not $winRmWasRunning) {
|
||||||
Stop-Service WinRM -Force -ErrorAction SilentlyContinue
|
Stop-Service WinRM -Force -NoWait -WarningAction SilentlyContinue `
|
||||||
|
-ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
Remove-Item -LiteralPath $temporaryRoot -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item -LiteralPath $temporaryRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
$DomainCredential = $null
|
$DomainCredential = $null
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ Bootstrap reproducible para el laboratorio SGU.
|
|||||||
- El Auth Broker resuelve la dirección guardada de administrativos y docentes mediante `GetDireccion`, `GetLocalidadListado` y `GetColoniasListado`, evitando conservar los valores transitorios `Seleccione...` de los controles dinámicos de SGU.
|
- El Auth Broker resuelve la dirección guardada de administrativos y docentes mediante `GetDireccion`, `GetLocalidadListado` y `GetColoniasListado`, evitando conservar los valores transitorios `Seleccione...` de los controles dinámicos de SGU.
|
||||||
- El enrolamiento y la reparación de clientes Windows crean y verifican idempotentemente la cuenta local estándar `alumno`, sin pertenencia al grupo de administradores.
|
- El enrolamiento y la reparación de clientes Windows crean y verifican idempotentemente la cuenta local estándar `alumno`, sin pertenencia al grupo de administradores.
|
||||||
- La descripción de la cuenta local administrada respeta el límite de 48 caracteres de Windows 10 Enterprise.
|
- La descripción de la cuenta local administrada respeta el límite de 48 caracteres de Windows 10 Enterprise.
|
||||||
|
- La validación de expiración de contraseña usa el indicador de cuenta compatible con Windows 10 y 11, en lugar de una propiedad que Windows 10 no expone.
|
||||||
- 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 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.
|
- 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.
|
- Windows Home se detecta y se rechaza con una explicación, ya que no admite unión a Active Directory ni RDP host.
|
||||||
|
|||||||
@@ -6,6 +6,14 @@ $ErrorActionPreference = 'Stop'
|
|||||||
$userName = 'alumno'
|
$userName = 'alumno'
|
||||||
$plainTextPassword = 'ingenieria'
|
$plainTextPassword = 'ingenieria'
|
||||||
$description = 'Cuenta local estandar SGU para recuperacion'
|
$description = 'Cuenta local estandar SGU para recuperacion'
|
||||||
|
$passwordNeverExpiresFlag = 0x10000
|
||||||
|
|
||||||
|
function Get-LocalUserFlags {
|
||||||
|
param([Parameter(Mandatory)][string]$Name)
|
||||||
|
|
||||||
|
$directoryEntry = [ADSI]("WinNT://$env:COMPUTERNAME/$Name,user")
|
||||||
|
return [int]$directoryEntry.InvokeGet('UserFlags')
|
||||||
|
}
|
||||||
|
|
||||||
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||||
$principal = [Security.Principal.WindowsPrincipal]::new($identity)
|
$principal = [Security.Principal.WindowsPrincipal]::new($identity)
|
||||||
@@ -40,6 +48,16 @@ try {
|
|||||||
-Description $description | Out-Null
|
-Description $description | Out-Null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Windows 10's Get-LocalUser object has PasswordExpires but does not expose
|
||||||
|
# PasswordNeverExpires. Enforce and verify the underlying UF_DONT_EXPIRE_PASSWD
|
||||||
|
# flag so the result is consistent across Windows 10 and Windows 11.
|
||||||
|
$directoryEntry = [ADSI]("WinNT://$env:COMPUTERNAME/$userName,user")
|
||||||
|
$userFlags = [int]$directoryEntry.InvokeGet('UserFlags')
|
||||||
|
if (($userFlags -band $passwordNeverExpiresFlag) -eq 0) {
|
||||||
|
$directoryEntry.InvokeSet('UserFlags', ($userFlags -bor $passwordNeverExpiresFlag))
|
||||||
|
$directoryEntry.CommitChanges()
|
||||||
|
}
|
||||||
|
|
||||||
$user = Get-LocalUser -Name $userName -ErrorAction Stop
|
$user = Get-LocalUser -Name $userName -ErrorAction Stop
|
||||||
$administratorsSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-544')
|
$administratorsSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-544')
|
||||||
$usersSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-545')
|
$usersSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-545')
|
||||||
@@ -74,11 +92,16 @@ if (@($verifiedAdministrators).SID.Value -contains $verifiedUser.SID.Value) {
|
|||||||
if ($verifiedUsers.SID.Value -notcontains $verifiedUser.SID.Value) {
|
if ($verifiedUsers.SID.Value -notcontains $verifiedUser.SID.Value) {
|
||||||
throw "The local account '$userName' does not belong to the local Users group."
|
throw "The local account '$userName' does not belong to the local Users group."
|
||||||
}
|
}
|
||||||
|
$verifiedPasswordNeverExpires =
|
||||||
|
((Get-LocalUserFlags -Name $userName) -band $passwordNeverExpiresFlag) -ne 0
|
||||||
|
if (-not $verifiedPasswordNeverExpires) {
|
||||||
|
throw "The local account '$userName' password is not configured to never expire."
|
||||||
|
}
|
||||||
|
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
UserName = $verifiedUser.Name
|
UserName = $verifiedUser.Name
|
||||||
Enabled = $verifiedUser.Enabled
|
Enabled = $verifiedUser.Enabled
|
||||||
IsAdministrator = $false
|
IsAdministrator = $false
|
||||||
IsStandardUser = $true
|
IsStandardUser = $true
|
||||||
PasswordNeverExpires = $verifiedUser.PasswordNeverExpires
|
PasswordNeverExpires = $verifiedPasswordNeverExpires
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ $interactiveLogonPolicyPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\P
|
|||||||
$settingsPath = Join-Path $env:ProgramData 'SGU\CredentialProvider\settings.json'
|
$settingsPath = Join-Path $env:ProgramData 'SGU\CredentialProvider\settings.json'
|
||||||
$issues = [Collections.Generic.List[string]]::new()
|
$issues = [Collections.Generic.List[string]]::new()
|
||||||
$standardLocalUserName = 'alumno'
|
$standardLocalUserName = 'alumno'
|
||||||
|
$passwordNeverExpiresFlag = 0x10000
|
||||||
|
|
||||||
$computer = Get-CimInstance Win32_ComputerSystem
|
$computer = Get-CimInstance Win32_ComputerSystem
|
||||||
if ($RequireDomainJoined -and -not $computer.PartOfDomain) {
|
if ($RequireDomainJoined -and -not $computer.PartOfDomain) {
|
||||||
@@ -93,8 +94,7 @@ $standardLocalUserPresent = [bool]$standardLocalUser
|
|||||||
$standardLocalUserEnabled = $standardLocalUserPresent -and $standardLocalUser.Enabled
|
$standardLocalUserEnabled = $standardLocalUserPresent -and $standardLocalUser.Enabled
|
||||||
$standardLocalUserIsAdministrator = $false
|
$standardLocalUserIsAdministrator = $false
|
||||||
$standardLocalUserInUsersGroup = $false
|
$standardLocalUserInUsersGroup = $false
|
||||||
$standardLocalUserPasswordNeverExpires =
|
$standardLocalUserPasswordNeverExpires = $false
|
||||||
$standardLocalUserPresent -and $standardLocalUser.PasswordNeverExpires
|
|
||||||
if ($standardLocalUserPresent) {
|
if ($standardLocalUserPresent) {
|
||||||
$administratorsSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-544')
|
$administratorsSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-544')
|
||||||
$usersSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-545')
|
$usersSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-545')
|
||||||
@@ -106,6 +106,16 @@ if ($standardLocalUserPresent) {
|
|||||||
$administratorMembers.SID.Value -contains $standardLocalUser.SID.Value
|
$administratorMembers.SID.Value -contains $standardLocalUser.SID.Value
|
||||||
$standardLocalUserInUsersGroup =
|
$standardLocalUserInUsersGroup =
|
||||||
$standardMembers.SID.Value -contains $standardLocalUser.SID.Value
|
$standardMembers.SID.Value -contains $standardLocalUser.SID.Value
|
||||||
|
try {
|
||||||
|
$directoryEntry = [ADSI]("WinNT://$env:COMPUTERNAME/$standardLocalUserName,user")
|
||||||
|
$userFlags = [int]$directoryEntry.InvokeGet('UserFlags')
|
||||||
|
$standardLocalUserPasswordNeverExpires =
|
||||||
|
($userFlags -band $passwordNeverExpiresFlag) -ne 0
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
# Report the account as invalid when Windows cannot read its flags.
|
||||||
|
$standardLocalUserPasswordNeverExpires = $false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (-not $standardLocalUserPresent) {
|
if (-not $standardLocalUserPresent) {
|
||||||
$issues.Add("The required standard local user '$standardLocalUserName' is missing.")
|
$issues.Add("The required standard local user '$standardLocalUserName' is missing.")
|
||||||
@@ -120,7 +130,7 @@ elseif (-not $standardLocalUserInUsersGroup) {
|
|||||||
$issues.Add("The required standard local user '$standardLocalUserName' does not belong to the local Users group.")
|
$issues.Add("The required standard local user '$standardLocalUserName' does not belong to the local Users group.")
|
||||||
}
|
}
|
||||||
elseif (-not $standardLocalUserPasswordNeverExpires) {
|
elseif (-not $standardLocalUserPasswordNeverExpires) {
|
||||||
$issues.Add("The required standard local user '$standardLocalUserName' does not retain its enrollment password.")
|
$issues.Add("The required standard local user '$standardLocalUserName' password is not configured to never expire.")
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings = $null
|
$settings = $null
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
$repositoryRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
|
$repositoryRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
|
||||||
$localUserScriptPath = Join-Path $repositoryRoot 'scripts\Set-SguStandardLocalUser.ps1'
|
$localUserScriptPath = Join-Path $repositoryRoot 'scripts\Set-SguStandardLocalUser.ps1'
|
||||||
|
$enrollmentTestScriptPath = Join-Path $repositoryRoot 'scripts\Test-SguClientEnrollment.ps1'
|
||||||
|
|
||||||
$tokens = $null
|
$tokens = $null
|
||||||
$parseErrors = $null
|
$parseErrors = $null
|
||||||
@@ -28,4 +29,13 @@ Describe 'SGU Windows client enrollment scripts' {
|
|||||||
$source | Should Match "\$userName = 'alumno'"
|
$source | Should Match "\$userName = 'alumno'"
|
||||||
$source | Should Match "\$plainTextPassword = 'ingenieria'"
|
$source | Should Match "\$plainTextPassword = 'ingenieria'"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It 'uses the cross-version Windows account flag for password expiration' {
|
||||||
|
$localUserSource = Get-Content -LiteralPath $localUserScriptPath -Raw
|
||||||
|
$enrollmentTestSource = Get-Content -LiteralPath $enrollmentTestScriptPath -Raw
|
||||||
|
$localUserSource | Should Match '\$passwordNeverExpiresFlag = 0x10000'
|
||||||
|
$enrollmentTestSource | Should Match '\$passwordNeverExpiresFlag = 0x10000'
|
||||||
|
$localUserSource | Should Not Match '\$verifiedUser\.PasswordNeverExpires'
|
||||||
|
$enrollmentTestSource | Should Not Match '\$standardLocalUser\.PasswordNeverExpires'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user