Powershell : obtention des liens des GPO

Si la console gpmc.msc permet de parcourir toutes les GPO ainsi que leurs liens, cela n'est pas directement possible avec Powershell et la commande Get-GPO qui ne retournera que les informations de base de la GPO.

Afin de pouvoir obtenir les liens dans Powershell, il faut ruser un peu ; dans les deux scripts Powershell suivants, j'ai donc utilisé une technique de sioux consistant à réaliser un rapport au format XML de la GPO (grâce à Get-GPOReport) et à parcourir ledit fichier XML pour y identifier les liens grâce aux balises <LinksTo>.

Ce premier script liste toutes les GPO qui n'ont aucun lien, activé ou non :

Write-Host "Unlinked GPO listing script"
 Write-Host "==========================="
 Write-Host "Working… Please wait.`r`n"
 $GPOlist = Get-GPO -all
 foreach($GPO in $GPOList){
     $xmlreport = Get-GPOReport -Guid $GPO.Id -Report xml
     if($xmlreport.GPO.LinksTo.Count -eq 0){ Write-Host $GPO.DisplayName ; $count+=1}
 }
 Write-Host "`r`nUnlinked GPO count:"$count
 Write-Host "GPO parsed:"$gpolist.Length
 Write-Host "Done."

Ce deuxième script attend en paramètre le nom d'une GPO et retourne dans la console Powershell les objets auxquels cette GPO est liée. Par exemple, on appellera le script ainsi : .\win_gpolinks.ps1 -gpo "SRV-2016-Security-V3"

Param([string]$gpoinput)
 $gpo = Get-GPO $gpoinput
 $report = Get-GPOReport -Guid $gpo.Id -Report xml
 foreach($link in $report.GPO.LinksTo){
     Write-Host $link.SOMPath
 }

A noter qu'il est nécessaire d'avoir les RSAT d'installés sur la station (si ce n'est pas un DC) depuis laquelle le script est exécuté ; il peut également être nécessaire d'appeler Import-Module GroupPolicy pour exécuter les cmdlets Get-GPO et Get-GPOReport.

The account is not authorized to login from this station

J'ai obtenu cette erreur en tentant de monter un partage réseau d'une machine en Windows XP sur un Server 2016, suite à une migration d'un Server 2003 sur lequel tout fonctionnait bien.

Après comparaison de multiples clefs de registre sur des machines Windows XP similaires pour lesquelles la connexion du partage réseau était possible, j'ai fait chou blanc ; jusqu'à tomber sur ce réglage de GPO locale (les machines sont toutes en standalone, je n'ai donc pas de politique de domaine) :

Situé dans Configuration Ordinateur > Paramètres Windows > Paramètres de sécurité > Stratégies locales > Options de sécurité > Accès réseau : modèle de partage et de sécurité pour les comptes locaux, ce paramètre était réglé sur Classique pour la machine incriminée et sur Guest (invité) sur toutes les autres. Une fois le paramètre passé sur Guest, j'ai pu monter ce partage SMB.

Il semblerait donc que les versions suivantes de SMB présentes avec 2016 (3.1+) aient logiquement des politiques de sécurité renforcées par rapport au SMB 1.x livré avec 2003. Ce billet d'un blog TechNet offre plus d'informations concernant les évolutions de Server Message Block.

Powershell : harmonisation de la configuration DNS

Afin d'harmoniser la configuration DNS sur des serveurs situés sur différents sites géographiques, j'ai développé un script Powershell lié à une GPO qui l'exécute au démarrage.

Ce script récupère grâce au nom du serveur son emplacement et applique en fonction de ce dernier les bonnes adresses IP. Naturellement, il faudra adapter l'extraction de l'emplacement dans le nom de la machine en fonction de l'environnement sur lequel le script sera déployé ; de plus, le domaine sur lequel la carte est connectée sert d'identification de la carte réseau employée pour la résolution DNS.

$location = (hostname).Substring(2,3)
switch($location){
"PAR" { $dnslist = '("192.168.1.1","192.168.1.2","192.168.2.1")' }
"BXL" { $dnslist = '("192.168.2.1","192.168.2.2","192.168.1.1")' }
"BER" { $dnslist = '("192.168.3.1","192.168.3.2","192.168.2.1")' }
"LDN" { $dnslist = '("192.168.4.1","192.168.4.2","192.168.3.1")' }
"NYC" { $dnslist = '("192.168.5.1","192.168.1.1","192.168.4.1")' }
}
$cards = Get-NetIPConfiguration
foreach($card in $cards){
if($card.NetProfile.Name -eq "dundermifflin.local") { $index = $card.InterfaceIndex }
}

$query = "Set-DnsClientServerAddress -InterfaceIndex $index -ServerAddresses $dnslist"
Invoke-Expression $query

Ce snippet fonctionne si par exemple mes serveurs ont une nomenclature de nommage comme celle-ci : <OS><Environnement><Emplacement><Rôle><ID>, qui pourrait donner par exemple pour un contrôleur de domaine de production WPLDNDC01 ou un serveur PostgreSQL de recette LRBXLPG03.

Powershell : GPO Remote Updater

Si vous avez suivi mes derniers articles, vous n'êtes pas sans savoir que j'ai travaillé sur le Windows Update Delivery Optimization et sur des GPO en lien avec ce composant.

J'ai développé un script Powershell à interface graphique permettant d'exécuter à distance un gpupdate, soit sur un ordinateur unique, soit sur chaque ordinateur d'un groupe ActiveDirectory.

Il est possible de choisir les paramètres à mettre à jour et de mettre un timer sur l'exécution du gpupdate ; dans ce dernier cas, le traitement se termine lorsque la commande est reçue par l'ordinateur distant étant donné que c'est ce dernier qui effectue le décompte jusqu'au lancement d'un gpupdate.

A noter que la commande Invoke-GPUpdate ne réalise pour autant pas une mise à jour silencieuse des éléments de GPO sur les ordinateurs, il convient donc de communiquer avant d'exécuter le script sur tout un groupe d'ordinateurs en cours d'utilisation. Je vous renvoie à la documentation de la commande pour plus d'informations sur les versions de Windows supportés et sur les ports qui doivent être ouverts dans les firewall afin que la communication puisse être établie.