9 sept. 2015

[snippet] Comment s'approprier rapidement des profils itinérants ?

Vous voulez vous approprier tous les profils itinérants Windows XP ? Mais si vous faites ça, les utilisateurs n'auront plus accès à leur profils itinérant et obtiendrons une erreur à l'ouverture de session.
Le profil itinérant possède une ACL NTFS qui indique que l'utilisateur du profil est le propriétaire du répertoire et des fichiers. L'administrateur ne peut pas accéder à ces fichiers, car il ne figure pas dans l'ACL par défaut. Une GPO existe pour rajouter le groupe Administrateurs dans l'ACL à la création du répertoire, mais admettons que cette GPO ne s'applique pas ou a été créée après les répertoires.
Le but du jeu est d'ajouter le groupe Administrateurs dans l'ACL de chaque répertoire. Or, pour modifier une ACL, il faut pouvoir y accéder, ce qui n'est pas le cas... La seule façon est de s'approprier le répertoire (ce qui va remplacer l'ACL existante par une ACL vierge, avec pour seule entrée le nouveau propriétaire). En faisant cela, les utilisateurs n'auront donc plus le droit d'accéder à leur propre profil. Il faut rajouter l'utilisateur dans l'ACL en contrôle total, et ce, récursivement pour les fichiers existants.

Attention : pour que Windows autorise de charger un profil itinérant, même si l'utilisateur a un contrôle total sur tous ses fichiers, il faut que le propriétaire du répertoire soit : soit le compte utilisateur soit le groupe Administrateurs. S'il s'agit d'un autre compte, même le compte Administrateur, le chargement échouera.

Voici le script powershell :

# répertoire à scanner
$dir = "D:\profils"

$profils = Get-ChildItem -Path $dir -Force -ea 0

$profils | ForEach-Object {
    $rep = $_
    if($rep.Mode.startsWith('d')) { # on ignore les fichiers
        $user = $_.Fullname.Split('\')[2]
        $owner = $acl = $null
        $acl = $rep.GetAccessControl()
        $owner = $acl.Owner
        if($owner -ne 'BUILTIN\Administrateurs' -and $owner -ne 'BUILTIN\Administrators') { # le propriétaire n'est pas déjà administrateur, on ne fait rien
            echo "$user MAUVAIS OWNER!"
        }
        else {
            $found =  $false
            $acl.Access|Where-Object{$_.IdentityReference.ToString() -ieq $user}|ForEach-Object{$found=$true} # on vérifie si le répertoire possède déjà l'ACL...
            if($found) {
                Write-Host -fore gray "$user have rights ($owner)"
            }
            else {
                write-host -fore blue "Il faut ajouter DOMAINE\$user."
                $NTuser = New-Object System.Security.Principal.NTAccount("DOMAINE\$user")
                $access = [System.Security.AccessControl.FileSystemRights]::FullControl
                $heritage = [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit
                $heritagefile = [System.Security.AccessControl.InheritanceFlags]::None
                $propa = [System.Security.AccessControl.PropagationFlags]::None
                $allow = [System.Security.AccessControl.AccessControlType]::Allow
                $ace = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAINE\$user",$access,$heritage,$propa,$allow) # on cré une ACE pour répertoire
                $acefile = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAINE\$user",$access,$heritagefile,$propa,$allow) # on cré une ACE pour les fichiers
                $acl.AddAccessRule($ace)
                if(!$?) {
                    echo "Impossible de créer l'ACL"
                }
                else { # l'ACL est OK, on l'applique
                    $rep.SetAccessControl($acl)
                    if($?) { # on répète récursivement aux fichiers et répertoires déjà existants
                        echo "Appropriation récursive de $($rep.Fullname)."
                        $aclfile = $null
                        Get-ChildItem -Path $rep.FullName -Force -Recurse | ForEach-Object {
                            if($_.Mode.StartsWith('d')) { # répertoire...
                                $_.SetAccessControl($acl)
                            }
                            else { # fichier...
                                $aclfile = $_.GetAccessControl() # doit recréer l'ACL à chaque fois pour les fichiers
                                $aclfile.AddAccessRule($acefile)
                                $_.SetAccessControl($aclfile)
                            }
                        }
                        Write-Host -fore green "`r`n$user : OK"
                    }
                    else {
                        Write-Host -fore red "`r`n$user : ERR"
                    }
                }
            }
        }
    }
}

Il est utile pour l'administrateur d'avoir accès au contenu des profils pour vérifier les abus de stockage de fichiers (notamment car le contenu du profil est "streamé" à l'ouverture de la session, contrairement au contenu d'un lecteur réseau ou d'une redirection de Mes documents).