Powershell : alimentation d'un groupe AD à partir des ACL

J'ai développé ce script Powershell afin de séparer les utilisateurs de plusieurs serveurs de fichiers dans des groupes ActiveDirectory liées à une liste de distribution Exchange. Ainsi, en cas de downtime prévu d'un serveur, il suffit d'envoyer une communication au groupe AD.

Ce script récupère les groupes AD placés dans les ACL des répertoires partagés, vide le groupe en question puis le repeuple à partir des utilisateurs qu'il a récupéré dans les groupes. Un filtre est fait sur l'OU contenant les utilisateurs afin de ne pas inclure d'éventuels comptes de service. Naturellement, on adaptera les filtres (ici, on recherche des groupes, mais on peut très bien lister directement les utilisateurs) et la troncature de la chaîne en fonction de ses besoins.

function update {
	param([string] $srv)
	Get-ADGroupMember "_users-$srv" | foreach { Remove-AdGroupMember "_users-$srv" -Member $_ -Confirm:$false }
	$folders = get-childitem "\\$srv.dundermifflin.inc\d$\shares" | get-acl
	foreach($folder in $folders){
		$domacl = $folder.Access | where-object { $_.IdentityReference -like "DUNDERMIFFLIN\*" }
		foreach($acl in $domacl){
		$grpm = Get-ADGroupMember $acl.IdentityReference.Value.SubString(14,($acl.IdentityReference.Value.Length-14)) -Recursive
			foreach($mbr in $grpm) {
				$adu = Get-ADuser $mbr -Properties CanonicalName
				if($adu.CanonicalName -like "dundermifflin.inc/USERS/*") { Add-AdGroupMember -Identity "_users-$srv" -Members $mbr }
			}			
		}
	}
}

update("filesrv01")
update("filesrv02")
update("filesrv03")

Le script l'exécute donc pour 3 serveurs de fichiers différents afin de peupler trois groupes différents. Si des utilisateurs sont placés directement dans les ACL, alors la commande Get-ADGroupMember renverra une erreur mais celle-ci n'est pas fatale. Afin d'être toujours à jour, on pourra appeler ce script via une tâche planifiée toutes les semaines.

Le script est disponible en téléchargement dans une version commentée.

Exchange et Powershell : nettoyage des références caduques dans les ACL

Les ACL des boîtes aux lettres Exchange ne sont pas en synchronisation permanente avec l'ActiveDirectory, ce qui signifie que si l'on ajoute par exemple sur la boîte scranton@dundermifflin.inc l'utilisateur DUNDERMIFFLIN\jhalpert et que ce compte vient à disparaître de l'ActiveDirectory, alors cette boîte aura dans ses ACL une référence de type "S-1-5-***". Il se produit par exemple la même chose côté Windows si un compte de domaine est ajouté dans les profils locaux du système et que ce compte de domaine vient à disparaître.

Afin de faire un peu de nettoyage sur des boîtes aux lettres partagées, j'ai donc développé un script pour l'Exchange Management Shell (EMS) permettant de lister toutes les références à ces comptes qui n'existent plus. Cette liste est ensuite exportée au format CSV, ce qui permet ensuite de passer ce fichier si besoin dans un script supprimant ces références.

$Output = @()
$mailboxes = Get-Mailbox -ResultSize Unlimited
foreach($mailbox in $mailboxes){
	$acls = Get-MailboxPermission $mailbox | where-object { $_.User -like "S-1-5-21*" -and $_.IsInherited -eq $false -and $_.AccessRights -contains "FullAccess" }
	if($acls -ne $null){
		foreach ($acl in $acls) { 
			$obj = New-Object PSCustomObject
			$obj | Add-Member -MemberType NoteProperty -Name "Mailbox" -Value $mailbox.Name
			$obj | Add-Member -MemberType NoteProperty -Name "SID" -Value $acl.User
			$Output += $obj 
		}
	}
}
$Output | Export-CSV s1521-acl.csv -Encoding UTF8

Dans cet exemple, je ne touche qu'aux permissions qui ont été rajoutées manuellement (IsInherited -eq $false) et aux droits complets (FullAccess). Si je ne recommande pas de changer le premier critère, il est possible de changer FullAccess pour un autre valeur si besoin. Je vous renvoie vers la documentation Microsoft concernant la commande Get-MailboxPermission pour plus d'informations sur le sujet.

Une fois le fichier CSV obtenu, je peux me servir de ce snippet pour le parcourir et procéder à la suppression des entrées relevées :

$acls = Import-CSV s1521-acl.csv
foreach($acl in $acls){
	Write-Host "Processing"$acl.Mailbox"with SID"$acl.SID
	Remove-MailboxPermission -Identity $acl.Mailbox -User $acl.SID -AccessRights FullAccess -Confirm:$false
}

Ce premier script est disponible dans une version commentée à télécharger.

Répertoires DFS visibles sans autorisation d'accès

J'ai été confronté à un problème provenant de la bureautique. Des utilisateurs voyaient dans leur liste de répertoires partagés sous Windows des partages DFS auxquels ils n'avaient pas accès, en plus de leurs répertoires DFS usuels. Normalement, Windows n'affiche pas de répertoire partagé si l'utilisateur n'a pas d'accès en lecture. Par exemple, si l'on considère la racine \\dundermifflin.inc\ et 3 répertoires DFS Sales, Accounting et Boss, si l'utilisateur n'a accès qu'au dernier il ne peut pas voir les dossiers Sales et Accounting.

Or dans mon cas, ces répertoires étaient bien visibles. La cause provient de la manière dont les permissions ont été positionnées dans la console DFS. Lors de la création d'un répertoire DFS, il est possible de positionner les privilèges de deux manières : en utilisant soit les permissions NTFS, soit DFS.

En choisissant l'option Use inherited permissions from the local file system, Windows ne va pas appliquer de permissions DFS sur le répertoire. Ainsi, comme son nom l'indique, les droits seront les mêmes que ceux positionnés sur le serveur qui héberge le répertoire en question. C'est justement ce réglage qui déclenche l'affichage dans l'explorateur. N'ayant aucune permission DFS de configurée, Windows ne sait pas avant d'interroger le serveur qui porte le répertoire si l'utilisateur a le droit de se connecter au non ; le répertoire est donc affiché. Ce n'est que lorsque l'utilisateur tente d'y accéder que Windows va récupérer les ACL et empêcher l'accès. Le comportement est par ailleurs expliqué dans la fenêtre ci-dessus.

La deuxième option, Set explicit view permissions on the DFS folder, place donc des permissions DFS directement sur le lien DFS (traduction de \\FileServer03.dundermifflin.inc\Shares vers \\dundermifflin.inc\shares). Ainsi, dès l'ouverture de l'explorateur, Windows lit ces ACL et n'affiche pas le répertoire puisqu'il sait que l'utilisateur n'y a pas accès.

Ce script Powershell permet d'afficher les répertoires DFS qui sont configurés avec la première option et qui apparaissent dans l'explorateur, si jamais vous souhaitez faire une passe complète sur tous vos shares DFS afin d'adopter une configuration homogène :

Param([Parameter(Mandatory=$true)][string] $Namespace)
$fNameSpace = "$Namespace\*"
Get-DfsnFolder $fNameSpace | where-object { (Get-DfsnAccess $_.Path) -eq $null }

Il suffit de l'appeler de cette manière :

.\DFS-NoPerm.ps1 -Namespace \\dundermifflin.inc\shares

Octroi de droits à un compte sur un service grâce à subinacl

En recherchant un moyen d'accorder les droits de démarrage / arrêt sur un service particulier pour un compte d'utilisateur standard, je suis tombé sur cet article sur Serverfault. Le but était d'éviter d'accorder des privilèges d'administration à l'utilisateur en question.

Il existe donc un outil nommé SubInACL, qui fait partie du Windows Resource Kit (aux côtés de nombreux autres outils que je connaissais comme LockOutStatus). Cet outil qui s'exécute en ligne de commande permet de choisir précisément quels privilèges accorder sur un service pour un utilisateur, qu'il soit local ou du domaine.

J'ai testé cet outil sur un serveur de test en 2008 R2 et appliqué le fonctionnement sur un 2016 ; son exécution est très simple. Microsoft explique toute la syntaxe disponible à ce lien. Si je souhaite accorder à l'utilisateur dschrute le droit de voir l'état et de relancer le service NTP, je vais devoir envoyer cette instruction :

subinacl.exe /service w32time /GRANT=DUNDERMIFFLIN\dschrute=STO

Voici sur un Server 2016, le résultat de la commande pour le service Windows Update :

Si SubInACL n'est plus disponible sur le site de Microsoft, il est disponible en téléchargement sur le miroir du blog à ce lien.