From 7986b76e35e7684b18c29d4b77310161567be2ac Mon Sep 17 00:00:00 2001 From: Alejandro Rosales Date: Fri, 18 Sep 2026 09:06:43 -0600 Subject: [PATCH] Disable Fast User Switching on domain clients --- docs/client-enrollment.md | 4 ++++ scripts/Install-CredentialProvider.ps1 | 8 ++++++++ scripts/Set-SguDomainComputerPolicies.ps1 | 1 + scripts/Test-SguClientEnrollment.ps1 | 15 +++++++++++++++ tests/ClientEnrollmentScripts.Tests.ps1 | 11 +++++++++++ 5 files changed, 39 insertions(+) diff --git a/docs/client-enrollment.md b/docs/client-enrollment.md index 3097298..b0a0f0f 100644 --- a/docs/client-enrollment.md +++ b/docs/client-enrollment.md @@ -36,6 +36,10 @@ contrario, el contenedor de equipos configurado en AD. Los parámetros explícitamente. Para otra cuenta, editar el usuario sugerido como `DOMINIO\usuario` o `usuario@dominio`. No se guardan contraseñas. +El enrolamiento también oculta las entradas de Cambio rápido de usuario mediante +una política de equipo. Docentes, administrativos y alumnos conservan la opción +de cerrar sesión, pero no pueden dejar una sesión abierta para cambiar a otra. + Si la IPv4 proporcionada es pública, el mismo flujo configura automáticamente la conectividad directa. Después de autenticar WinRM, el servidor crea o reutiliza un certificado DoH, publica DNS cifrado en TCP 443 y devuelve únicamente su diff --git a/scripts/Install-CredentialProvider.ps1 b/scripts/Install-CredentialProvider.ps1 index c483e72..5d9d008 100644 --- a/scripts/Install-CredentialProvider.ps1 +++ b/scripts/Install-CredentialProvider.ps1 @@ -314,6 +314,11 @@ if ($PSCmdlet.ShouldProcess($installPath, 'Install and register the SGU Credenti -Value 1 ` -PropertyType DWord ` -Force | Out-Null + New-ItemProperty -Path $interactiveLogonPolicyPath ` + -Name HideFastUserSwitching ` + -Value 1 ` + -PropertyType DWord ` + -Force | Out-Null if (-not (Test-Path -LiteralPath $defaultProviderPolicyPath)) { New-Item -Path $defaultProviderPolicyPath -Force | Out-Null } @@ -344,6 +349,9 @@ catch { LastSignedInUserHidden = (Get-ItemPropertyValue ` -LiteralPath $interactiveLogonPolicyPath ` -Name DontDisplayLastUserName) -eq 1 + FastUserSwitchingHidden = (Get-ItemPropertyValue ` + -LiteralPath $interactiveLogonPolicyPath ` + -Name HideFastUserSwitching) -eq 1 LocalUserEnumerationDisabled = (Get-ItemPropertyValue ` -LiteralPath $defaultProviderPolicyPath ` -Name EnumerateLocalUsers) -eq 0 diff --git a/scripts/Set-SguDomainComputerPolicies.ps1 b/scripts/Set-SguDomainComputerPolicies.ps1 index 9400fb1..dc6361e 100644 --- a/scripts/Set-SguDomainComputerPolicies.ps1 +++ b/scripts/Set-SguDomainComputerPolicies.ps1 @@ -99,6 +99,7 @@ $policies = @( @{ Key = $credentialProviderPolicyKey; Name = 'DefaultCredentialProvider'; Type = 'String'; Value = $providerClassId }, @{ Key = $credentialProviderPolicyKey; Name = 'EnumerateLocalUsers'; Type = 'DWord'; Value = 0 }, @{ Key = $interactiveLogonPolicyKey; Name = 'DontDisplayLastUserName'; Type = 'DWord'; Value = 1 }, + @{ Key = $interactiveLogonPolicyKey; Name = 'HideFastUserSwitching'; Type = 'DWord'; Value = 1 }, # Use Windows' native default account image for named user tiles. LogonUI # retains ownership of the anonymous Other user tile and its circular mask. diff --git a/scripts/Test-SguClientEnrollment.ps1 b/scripts/Test-SguClientEnrollment.ps1 index 481f8b7..1f615cd 100644 --- a/scripts/Test-SguClientEnrollment.ps1 +++ b/scripts/Test-SguClientEnrollment.ps1 @@ -92,6 +92,20 @@ if (-not $lastSignedInUserHidden) { $issues.Add('The last signed-in user is not hidden from LogonUI.') } +$fastUserSwitchingHidden = $false +try { + $fastUserSwitchingHidden = (Get-ItemPropertyValue ` + -LiteralPath $interactiveLogonPolicyPath ` + -Name HideFastUserSwitching ` + -ErrorAction Stop) -eq 1 +} +catch { + # Report the missing or unreadable policy as a failed enrollment check. +} +if (-not $fastUserSwitchingHidden) { + $issues.Add('Fast User Switching entry points are not hidden.') +} + $localUserEnumerationDisabled = $false try { $localUserEnumerationDisabled = (Get-ItemPropertyValue ` @@ -279,6 +293,7 @@ $result = [pscustomobject]@{ ProviderBinaryPresent = [bool]$providerBinaryPresent DefaultProviderConfigured = $defaultProviderConfigured LastSignedInUserHidden = $lastSignedInUserHidden + FastUserSwitchingHidden = $fastUserSwitchingHidden LocalUserEnumerationDisabled = $localUserEnumerationDisabled PasswordProviderPreserved = $passwordProviderPreserved StandardLocalUserPresent = $standardLocalUserPresent diff --git a/tests/ClientEnrollmentScripts.Tests.ps1 b/tests/ClientEnrollmentScripts.Tests.ps1 index 039c7d6..eddcf53 100644 --- a/tests/ClientEnrollmentScripts.Tests.ps1 +++ b/tests/ClientEnrollmentScripts.Tests.ps1 @@ -4,6 +4,8 @@ $enrollmentTestScriptPath = Join-Path $repositoryRoot 'scripts\Test-SguClientEnr $packageScriptPath = Join-Path $repositoryRoot 'scripts\New-SguBootstrapPackages.ps1' $releaseScriptPath = Join-Path $repositoryRoot 'scripts\Publish-GiteaRelease.ps1' $azureLauncherPath = Join-Path $repositoryRoot 'scripts\Start-SguAzureClientEnrollment.cmd' +$credentialProviderInstallerPath = Join-Path $repositoryRoot 'scripts\Install-CredentialProvider.ps1' +$computerPolicyScriptPath = Join-Path $repositoryRoot 'scripts\Set-SguDomainComputerPolicies.ps1' $tokens = $null $parseErrors = $null @@ -72,4 +74,13 @@ Describe 'SGU Windows client enrollment scripts' { Should Be $true $azureLauncher | Should Match '-PauseOnError' } + + It 'hides Fast User Switching during enrollment and through computer policy' { + (Get-Content -LiteralPath $credentialProviderInstallerPath -Raw) | + Should Match 'HideFastUserSwitching' + (Get-Content -LiteralPath $enrollmentTestScriptPath -Raw) | + Should Match 'FastUserSwitchingHidden' + (Get-Content -LiteralPath $computerPolicyScriptPath -Raw) | + Should Match "Name = 'HideFastUserSwitching'; Type = 'DWord'; Value = 1" + } }