Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01e0ee5ac4 | ||
|
|
c47913e81d |
@@ -111,7 +111,9 @@ For a public Azure VM, use
|
||||
optional Azure P2S gateway or direct enrollment restricted to explicit public
|
||||
source CIDRs. P2S deployments also provision private Azure Files storage for
|
||||
role-based roaming: `AL` redirects only Documents/Desktop, while `AD` and `DO`
|
||||
can mount an FSLogix VHDX profile after the post-domain setup step.
|
||||
use an FSLogix VHDX profile after the post-domain setup step. Existing public
|
||||
Azure Files deployments automatically use FSLogix Cloud Cache locally instead
|
||||
of performing all profile I/O across WAN SMB.
|
||||
|
||||
Never disable the built-in Microsoft password Credential Provider. It is the
|
||||
supported recovery path if a third-party provider fails to load.
|
||||
|
||||
@@ -84,7 +84,9 @@ Azure P2S deployments can add a dedicated, private Azure Files account. Student
|
||||
accounts (`AL`) keep a non-authoritative local profile and redirect only
|
||||
Documents/Desktop. Administrative and professor accounts (`AD`/`DO`) receive an
|
||||
FSLogix VHDX profile container through object-specific settings keyed to their
|
||||
AD security-group SIDs. The storage account uses AD DS Kerberos with AES-256;
|
||||
AD security-group SIDs. Private endpoints mount the VHDX directly; public WAN
|
||||
endpoints use a local FSLogix Cloud Cache synchronized to Azure Files so profile
|
||||
I/O does not block on every SMB round trip. The storage account uses AD DS Kerberos with AES-256;
|
||||
share-root ACLs use `CREATOR OWNER` so users cannot browse one another's data.
|
||||
The bootstrap staging account is deliberately separate. See
|
||||
[user-roaming.md](user-roaming.md) for rollout and recovery constraints.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# SGU Credential Provider 0.6.3
|
||||
|
||||
Corrige el primer inicio de sesión de perfiles completos `AD`/`DO` cuando Azure
|
||||
Files se consume mediante su endpoint público.
|
||||
|
||||
## Cambios
|
||||
|
||||
- `Enable-SguAzureUserRoaming.ps1` selecciona automáticamente FSLogix Cloud
|
||||
Cache para endpoints públicos y conserva el montaje directo para endpoints
|
||||
privados.
|
||||
- Cloud Cache realiza el I/O del perfil sobre el VHDX local y sincroniza con
|
||||
Azure Files, evitando que la latencia WAN de SMB bloquee cada operación.
|
||||
- La GPO elimina de forma efectiva `VHDLocations` al activar `CCDLocations`,
|
||||
incluyendo equipos que habían aplicado la política directa anterior.
|
||||
- Se impide el retorno silencioso a un perfil local o temporal cuando FSLogix
|
||||
no puede registrar el contenedor.
|
||||
- El cierre de sesión deja de esperar indefinidamente por un proveedor remoto:
|
||||
se limita a 60 segundos y conserva la caché local si vence el plazo.
|
||||
- La documentación agrega capacidad de disco, validación del registro efectivo
|
||||
y rutas de diagnóstico para ambos modos.
|
||||
|
||||
## Validación del despliegue
|
||||
|
||||
- Se eliminó únicamente el perfil piloto fallido de `AD017045` en `AF-03`; la
|
||||
cuenta de Active Directory se conservó.
|
||||
- La GPO `SGU - AD-DO FSLogix profiles` quedó en Cloud Cache para los SID de
|
||||
`SGU-Administrativos` y `SGU-Docentes`; `VHDLocations` ya no aparece en el
|
||||
registro efectivo de `AF-03`.
|
||||
- El nuevo inicio de `AD017045` creó la caché y el proxy locales, agregó la
|
||||
redirección del perfil al VHDX y completó `LoadProfile` en 4.649 segundos, sin
|
||||
error 258, perfil temporal ni retorno local.
|
||||
- Pasaron 70 pruebas Pester, 41 pruebas de `SGU.AuthBroker.Core`, 16 de
|
||||
`SGU.AuthBroker` y 6 del Credential Provider. La solución compiló sin errores.
|
||||
|
||||
## Descargas
|
||||
|
||||
- `sgu-windows-client-bootstrap-0.6.3.zip`
|
||||
- `sgu-server-bootstrap-0.6.3.zip`
|
||||
- `sgu-linux-client-bootstrap-0.6.3.zip`
|
||||
- `sgu-azure-infrastructure-0.6.3.zip`
|
||||
- `SHA256SUMS-0.6.3.txt`
|
||||
|
||||
Verifique los hashes SHA-256 antes de ejecutar los paquetes. No se incluyen
|
||||
credenciales, claves de almacenamiento ni artefactos temporales del despliegue.
|
||||
+37
-4
@@ -6,7 +6,7 @@ cada tipo de cuenta SGU:
|
||||
| Rol | Datos conservados | Implementación |
|
||||
| --- | --- | --- |
|
||||
| `AL` | `Desktop` y `Documents` | Redirección de carpetas a Azure Files; el resto del perfil local no es autoritativo y no se copia al iniciar o cerrar sesión. |
|
||||
| `AD` / `DO` | Perfil completo | Un contenedor VHDX único de FSLogix montado desde Azure Files. |
|
||||
| `AD` / `DO` | Perfil completo | FSLogix: montaje directo del VHDX con endpoint privado o Cloud Cache local sincronizada con Azure Files cuando el endpoint es público. |
|
||||
|
||||
Linux conserva su solución nativa de directorios personales; no intenta montar
|
||||
un perfil de Windows.
|
||||
@@ -36,6 +36,24 @@ esa ejecución; después se establece `defaultAction=Deny` y se deja únicamente
|
||||
red institucional autorizada. En el despliegue LCI actual esa regla final es
|
||||
`200.13.89.0/24`.
|
||||
|
||||
El modo `-StaffProfileStorageMode Auto` es el predeterminado. Selecciona
|
||||
`Direct` con un endpoint privado y `CloudCache` con uno público. Cloud Cache
|
||||
mantiene el VHDX de trabajo en `C:\ProgramData\FSLogix\Cache` y sincroniza sus
|
||||
cambios con Azure Files, evitando que cada operación del perfil dependa de la
|
||||
latencia WAN de SMB. `CCDLocations` y `VHDLocations` son mutuamente excluyentes:
|
||||
el configurador elimina de forma efectiva el valor obsoleto al cambiar de modo,
|
||||
incluso en clientes que ya habían aplicado la GPO anterior. Puede forzarse un
|
||||
modo con `-StaffProfileStorageMode Direct` o `CloudCache`, pero `Direct` sobre
|
||||
un endpoint público sólo debe usarse para diagnóstico.
|
||||
|
||||
Cloud Cache necesita espacio local suficiente para el perfil (30 GB de máximo
|
||||
por omisión), conserva la caché tras cerrar sesión y exige al menos un proveedor
|
||||
remoto sano al registrar o desmontar el perfil. Si el proveedor no completa la
|
||||
sincronización, el cierre espera como máximo 60 segundos y después conserva la
|
||||
caché local para reintentar; no la descarta. La GPO también impide el inicio
|
||||
con perfil temporal o local cuando FSLogix falla, para que una incidencia no
|
||||
produzca dos perfiles divergentes silenciosamente.
|
||||
|
||||
Azure Files se integra con el AD DS SGU, no con cuentas o claves guardadas en
|
||||
cada cliente. El script configura AES-256 para Kerberos, una ACL de mínimo
|
||||
privilegio con `CREATOR OWNER`, administradores y los grupos del rol, y permiso
|
||||
@@ -97,6 +115,14 @@ $parameters = @{
|
||||
.\payload\scripts\Enable-SguAzureUserRoaming.ps1 @parameters
|
||||
```
|
||||
|
||||
Para reutilizar una cuenta con endpoint público:
|
||||
|
||||
```powershell
|
||||
$parameters.EndpointAccess = 'Public'
|
||||
$parameters.StaffProfileStorageMode = 'Auto' # resuelve a CloudCache
|
||||
.\payload\scripts\Enable-SguAzureUserRoaming.ps1 @parameters
|
||||
```
|
||||
|
||||
La operación es idempotente. Crea `OU=AzureFilesConfig`, une la cuenta de
|
||||
almacenamiento al bosque y publica dos GPO:
|
||||
|
||||
@@ -156,15 +182,21 @@ Después de `gpupdate /force` y reiniciar un cliente:
|
||||
Resolve-DnsName "$($azure.UserRoamingStorageAccountName).file.core.windows.net"
|
||||
Test-NetConnection "$($azure.UserRoamingStorageAccountName).file.core.windows.net" -Port 445
|
||||
Get-Service frxsvc
|
||||
Get-ItemProperty 'HKLM:\SOFTWARE\FSLogix\Profiles'
|
||||
Get-ItemProperty 'HKLM:\SOFTWARE\FSLogix\Profiles\ObjectSpecific\<SID-del-grupo>'
|
||||
Get-ItemProperty 'HKLM:\SOFTWARE\SGU\FSLogixDeployment'
|
||||
& 'C:\Program Files\FSLogix\Apps\frx.exe' list-redirects
|
||||
```
|
||||
|
||||
La resolución debe devolver la IP privada del endpoint. Inicie primero con un
|
||||
En modo privado, la resolución debe devolver la IP privada del endpoint; en
|
||||
modo público debe devolver una dirección pública y TCP 445 debe estar permitido
|
||||
desde la red institucional. En Cloud Cache compruebe además que existe
|
||||
`C:\ProgramData\FSLogix\Cache` y que el registro efectivo contiene
|
||||
`CCDLocations`, pero no `VHDLocations`. Inicie primero con un
|
||||
`AL` nuevo y confirme las ubicaciones de Escritorio/Documentos; luego pruebe un
|
||||
`AD` o `DO` sin perfil local previo y confirme la creación de un VHDX en
|
||||
`profiles`. No active el borrado de perfiles locales ni despliegue a todos los
|
||||
`profiles`. Revise `%ProgramData%\FSLogix\Logs\Profile` para confirmar que el
|
||||
perfil se registró sin `ERROR: 258`, perfil temporal ni retorno a `C:\Users`.
|
||||
No active el borrado de perfiles locales ni despliegue a todos los
|
||||
usuarios hasta probar inicio, cierre, desconexión de VPN, cuota y restauración.
|
||||
|
||||
Referencias de Microsoft:
|
||||
@@ -173,4 +205,5 @@ Referencias de Microsoft:
|
||||
- [Permisos SMB para FSLogix](https://learn.microsoft.com/fslogix/how-to-configure-storage-permissions)
|
||||
- [Contenedores de perfil FSLogix](https://learn.microsoft.com/fslogix/how-to-configure-profile-containers)
|
||||
- [Configuración ObjectSpecific de FSLogix](https://learn.microsoft.com/fslogix/how-to-configure-object-specific-settings)
|
||||
- [Cloud Cache de FSLogix](https://learn.microsoft.com/fslogix/concepts-fslogix-cloud-cache)
|
||||
- [Redirección de carpetas](https://learn.microsoft.com/windows-server/storage/folder-redirection/deploy-folder-redirection)
|
||||
|
||||
@@ -23,6 +23,8 @@ param(
|
||||
[string]$StaffGpoName = 'SGU - AD-DO FSLogix profiles',
|
||||
[ValidateSet('Private', 'Public')]
|
||||
[string]$EndpointAccess = 'Private',
|
||||
[ValidateSet('Auto', 'Direct', 'CloudCache')]
|
||||
[string]$StaffProfileStorageMode = 'Auto',
|
||||
[ValidateRange(1024, 1048576)]
|
||||
[int]$FsLogixProfileSizeMiB = 30000,
|
||||
[string]$AzFilesHybridModulePath,
|
||||
@@ -161,6 +163,36 @@ function Set-SguGpoRegistryValue {
|
||||
}
|
||||
}
|
||||
|
||||
function Remove-SguGpoRegistryValue {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$GpoName,
|
||||
[Parameter(Mandatory)][string]$DomainName,
|
||||
[Parameter(Mandatory)][string]$Server,
|
||||
[Parameter(Mandatory)][string]$Key,
|
||||
[Parameter(Mandatory)][string]$ValueName
|
||||
)
|
||||
|
||||
if ($PSCmdlet.ShouldProcess("$GpoName :: $Key\$ValueName", 'Remove obsolete policy value')) {
|
||||
Remove-GPRegistryValue -Name $GpoName -Domain $DomainName -Server $Server `
|
||||
-Key $Key -ValueName $ValueName -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
function Set-SguGpoRegistryValueDeletion {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$GpoName,
|
||||
[Parameter(Mandatory)][string]$DomainName,
|
||||
[Parameter(Mandatory)][string]$Server,
|
||||
[Parameter(Mandatory)][string]$Key,
|
||||
[Parameter(Mandatory)][string]$ValueName
|
||||
)
|
||||
|
||||
Remove-SguGpoRegistryValue -GpoName $GpoName -DomainName $DomainName -Server $Server `
|
||||
-Key $Key -ValueName $ValueName
|
||||
Set-SguGpoRegistryValue -GpoName $GpoName -DomainName $DomainName -Server $Server `
|
||||
-Key $Key -ValueName "**del.$ValueName" -Type String -Value ''
|
||||
}
|
||||
|
||||
function Get-SguUnusedDriveName {
|
||||
$used = @(Get-PSDrive -PSProvider FileSystem | Select-Object -ExpandProperty Name)
|
||||
foreach ($name in @('Z', 'Y', 'X', 'W', 'V')) {
|
||||
@@ -350,6 +382,12 @@ $storageCredential = [PSCredential]::new(
|
||||
(ConvertTo-SecureString -String $storageKey -AsPlainText -Force))
|
||||
$profilesSharePath = "\\$fileEndpointHost\$FsLogixProfilesShareName"
|
||||
$redirectedFoldersSharePath = "\\$fileEndpointHost\$RedirectedFoldersShareName"
|
||||
$resolvedStaffProfileStorageMode = if ($StaffProfileStorageMode -eq 'Auto') {
|
||||
if ($EndpointAccess -eq 'Public') { 'CloudCache' } else { 'Direct' }
|
||||
}
|
||||
else {
|
||||
$StaffProfileStorageMode
|
||||
}
|
||||
$perUserRootRights = [Security.AccessControl.FileSystemRights]::CreateDirectories -bor
|
||||
[Security.AccessControl.FileSystemRights]::ListDirectory -bor
|
||||
[Security.AccessControl.FileSystemRights]::ReadAttributes -bor
|
||||
@@ -407,12 +445,54 @@ $fsLogixValues = [ordered]@{
|
||||
ReAttachIntervalSeconds = @{ Type = 'DWord'; Value = 15 }
|
||||
ReAttachRetryCount = @{ Type = 'DWord'; Value = 3 }
|
||||
SizeInMBs = @{ Type = 'DWord'; Value = $FsLogixProfileSizeMiB }
|
||||
VHDLocations = @{ Type = 'String'; Value = $profilesSharePath }
|
||||
VolumeType = @{ Type = 'String'; Value = 'VHDX' }
|
||||
}
|
||||
$cloudCacheOnlyValues = @(
|
||||
'CCDLocations',
|
||||
'CcdUnregisterTimeout',
|
||||
'ClearCacheOnForcedUnregister',
|
||||
'ClearCacheOnLogoff',
|
||||
'HealthyProvidersRequiredForRegister',
|
||||
'HealthyProvidersRequiredForUnregister',
|
||||
'PreventLoginWithFailure',
|
||||
'PreventLoginWithTempProfile'
|
||||
)
|
||||
if ($resolvedStaffProfileStorageMode -eq 'CloudCache') {
|
||||
$fsLogixValues.CCDLocations = @{
|
||||
Type = 'String'
|
||||
Value = "type=smb,name=`"SGU Azure Files`",connectionString=$profilesSharePath"
|
||||
}
|
||||
$fsLogixValues.CcdUnregisterTimeout = @{ Type = 'DWord'; Value = 60 }
|
||||
$fsLogixValues.ClearCacheOnForcedUnregister = @{ Type = 'DWord'; Value = 0 }
|
||||
$fsLogixValues.ClearCacheOnLogoff = @{ Type = 'DWord'; Value = 0 }
|
||||
$fsLogixValues.HealthyProvidersRequiredForRegister = @{ Type = 'DWord'; Value = 1 }
|
||||
$fsLogixValues.HealthyProvidersRequiredForUnregister = @{ Type = 'DWord'; Value = 1 }
|
||||
$fsLogixValues.PreventLoginWithFailure = @{ Type = 'DWord'; Value = 1 }
|
||||
$fsLogixValues.PreventLoginWithTempProfile = @{ Type = 'DWord'; Value = 1 }
|
||||
}
|
||||
else {
|
||||
$fsLogixValues.VHDLocations = @{ Type = 'String'; Value = $profilesSharePath }
|
||||
}
|
||||
Set-SguGpoRegistryValue -GpoName $staffGpo.DisplayName -DomainName $domainName `
|
||||
-Server $DomainController -Key 'HKLM\SOFTWARE\FSLogix\Apps' `
|
||||
-ValueName 'VHDCompactDisk' -Type DWord -Value 0
|
||||
foreach ($staffGroup in @($professorGroup, $administrativeGroup)) {
|
||||
$objectSpecificKey = "$fsLogixRoot\ObjectSpecific\$($staffGroup.SID.Value)"
|
||||
Set-SguGpoRegistryValueDeletion -GpoName $staffGpo.DisplayName -DomainName $domainName `
|
||||
-Server $DomainController -Key $objectSpecificKey -ValueName 'VHDCompactDisk'
|
||||
if ($resolvedStaffProfileStorageMode -eq 'CloudCache') {
|
||||
Set-SguGpoRegistryValueDeletion -GpoName $staffGpo.DisplayName -DomainName $domainName `
|
||||
-Server $DomainController -Key $objectSpecificKey -ValueName 'VHDLocations'
|
||||
}
|
||||
else {
|
||||
foreach ($obsoleteValue in $cloudCacheOnlyValues) {
|
||||
Set-SguGpoRegistryValueDeletion -GpoName $staffGpo.DisplayName -DomainName $domainName `
|
||||
-Server $DomainController -Key $objectSpecificKey -ValueName $obsoleteValue
|
||||
}
|
||||
}
|
||||
foreach ($setting in $fsLogixValues.GetEnumerator()) {
|
||||
Remove-SguGpoRegistryValue -GpoName $staffGpo.DisplayName -DomainName $domainName `
|
||||
-Server $DomainController -Key $objectSpecificKey -ValueName "**del.$($setting.Key)"
|
||||
Set-SguGpoRegistryValue -GpoName $staffGpo.DisplayName -DomainName $domainName `
|
||||
-Server $DomainController -Key $objectSpecificKey -ValueName $setting.Key `
|
||||
-Type $setting.Value.Type -Value $setting.Value.Value
|
||||
@@ -423,6 +503,7 @@ foreach ($staffGroup in @($professorGroup, $administrativeGroup)) {
|
||||
StorageAccountName = $StorageAccountName
|
||||
FileEndpoint = $fileEndpointHost
|
||||
EndpointAccess = $EndpointAccess
|
||||
StaffProfileStorageMode = $resolvedStaffProfileStorageMode
|
||||
EndpointAddresses = $endpointAddresses
|
||||
PrivateEndpointAddresses = $privateAddresses
|
||||
DirectoryService = $directoryService
|
||||
@@ -434,6 +515,11 @@ foreach ($staffGroup in @($professorGroup, $administrativeGroup)) {
|
||||
StudentPolicy = $studentGpo.DisplayName
|
||||
StaffPolicy = $staffGpo.DisplayName
|
||||
StudentBehavior = 'Local non-authoritative profile; Documents and Desktop redirected without Offline Files pinning.'
|
||||
StaffBehavior = 'FSLogix VHDX profile container for SGU-Docentes and SGU-Administrativos only.'
|
||||
StaffBehavior = if ($resolvedStaffProfileStorageMode -eq 'CloudCache') {
|
||||
'FSLogix Cloud Cache profile container for SGU-Docentes and SGU-Administrativos only; local I/O is synchronized to Azure Files.'
|
||||
}
|
||||
else {
|
||||
'Direct FSLogix VHDX profile container for SGU-Docentes and SGU-Administrativos only.'
|
||||
}
|
||||
ExistingStaffLocalProfilesDeleted = [bool]$DeleteExistingStaffLocalProfiles
|
||||
}
|
||||
|
||||
@@ -89,6 +89,24 @@ Describe 'SGU role-specific roaming policies' {
|
||||
$source | Should Match 'selected \$EndpointAccess endpoint'
|
||||
}
|
||||
|
||||
It 'uses local Cloud Cache automatically for public WAN profile storage' {
|
||||
(((Get-Command $configurationPath).Parameters['StaffProfileStorageMode'].Attributes |
|
||||
Where-Object { $_ -is [Management.Automation.ValidateSetAttribute] }).ValidValues -join ',') |
|
||||
Should Be 'Auto,Direct,CloudCache'
|
||||
$source = Get-Content -LiteralPath $configurationPath -Raw
|
||||
$source | Should Match "EndpointAccess -eq 'Public'\) \{ 'CloudCache' \}"
|
||||
$source | Should Match 'CCDLocations'
|
||||
$source | Should Match 'type=smb,name='
|
||||
$source | Should Match "ValueName 'VHDLocations'"
|
||||
$source | Should Match '\*\*del\.\$ValueName'
|
||||
$source | Should Match 'HealthyProvidersRequiredForRegister'
|
||||
$source | Should Match 'CcdUnregisterTimeout.*60'
|
||||
$source | Should Match 'ClearCacheOnForcedUnregister'
|
||||
$source | Should Match 'PreventLoginWithFailure'
|
||||
$source | Should Match "'HKLM\\SOFTWARE\\FSLogix\\Apps'"
|
||||
$source | Should Match "ValueName 'VHDCompactDisk'"
|
||||
}
|
||||
|
||||
It 'uses an AD computer identity with AES-256 Kerberos' {
|
||||
$source = Get-Content -LiteralPath $configurationPath -Raw
|
||||
$source | Should Match "DomainAccountType = 'ComputerAccount'"
|
||||
|
||||
Reference in New Issue
Block a user