Powershell : liste des homedirs orphelins V2

J’avais présenté dans un précédent article un script Powershell permettant de lister les homedirs orphelins, c’est à dire les homedirs dont le compte AD lié n’existe plus. Celui-ci se basait sur une vérification du nom du répertoire et testait la corrélation avec un utilisateur existant dans l’AD. Rapide mais peu robuste car un utilisateur changeant d’identifiant déjoue le script.

J’ai donc réalisé une v2 de ce script, en utilisant cette fois-ci l’instruction Get-Acl pour récupérer le propriétaire des répertoires. Chaque homedir possède en propriétaire un SID qui renvoie vers un utilisateur local ou du domaine. Si l’utilisateur du domaine est supprimé, alors le SID disparaît de l’annuaire… mais reste référencé en tant que propriétaire du homedir, comme on peut le voir sur cette capture d’écran du répertoire avec la colonne Owner affichée :

comptetest sur DOMAIN existe toujours par contre les comptes propriétaires des autres répertoires ont été supprimés de l’AD car Windows ne fait pas le lien entre le SID enregistré et un SID existant dans l’annuaire.      

Le script commenté est disponible en fin d’article et est prêt à être adapté à n’importe quel environnement.

function noexist{
Write-Host "Homedir $folderfullpath doesn't have any owner."
Add-Content -path "orphan-homedir.log" -Force -Value $folderfullpath
}

Write-Host "Orphan homedir listing script V2"
Write-Host "================================"
Write-Host ""
Clear-Content -path "orphan-homedir.log" -Force
for ($Line = 15; $Line -gt 0; $Line--) {
$RemoteServer = (Get-Content C:\homedir-srv-list.txt -TotalCount 15)[-$Line]
Write-Host "Building user homedir list on $RemoteServer"
$HomedirPath = "\\"+$RemoteServer+"\c$\homedir"
Add-Content -path "orphan-homedir.log" -Force -Value "`r`n$RemoteServer`r`n========"
$folderlist = Get-ChildItem $HomedirPath | select name
Write-Host "Checking directories ACLs"
foreach ($folder in $folderlist) {
$folderFullPath = $homedirpath+$folder.Name
$prop = Get-Acl $folderFullPath
if ($prop.Owner.Contains("S-1-5-21")) { noexist }
}
}
Write-Host "Please find in orphan-homedir.log the list of homedirs that don't have any linked AD account."
Write-Host "Bye"

Powershell : Export CSV d’une liste de KB WSUS

Afin de pouvoir communiquer sur les KB qui devront être prochainement appliqués sur les stations de travail pilotes, j’ai réalisé un script permettant de récupérer la liste des patchs qui sont en statut FailedOrNeeded et qui sont Unapproved dans WSUS, avec un filtre supplémentaire appliqué plus tard sur le nom afin de rejeter ceux qui concernent les serveurs et le .NET Framework.

De plus, je souhaitais uniquement récupérer les mises à jour qui ne sont pas Superseded, signifiant qu’elles ne sont pas écrasées ou incluses dans d’autres patchs (par exemple, le KB numéro 12345 est un patch cumulatif et contient les KB 2345 et 4567, par conséquent je ne veux pas tester ces deux derniers mais uniquement 12345) ; ce qui force une double requête, transmise dans le pipe.

Write-Host "WSUS Updates CSV Export Script"
Write-Host "=============================="
Write-Host `r`n
Write-Host "Retrieving unapproved and failed or needed WSUS Updates.`r`nThis might take a couple of minutes..."
$output = @() 
$UpdateList = Get-WsusUpdate -Approval Unapproved -Status FailedOrNeeded -Classification All | Where {($_.Update.IsSuperseded -eq $false) -and ($_.Update.KnowledgeBaseArticles -ne $null) }
Write-Host "Filtering and exporting to CSV..."
foreach ($Update in $UpdateList) { 
    if ($Update.Update.Title.Contains("Server") -eq $false -and $Update.Update.Title.Contains("Framework") -eq $false){
        $title = $Update.Update.Title
        $kbnumber = $Update.Update.KnowledgeBaseArticles
        $product = $Update.Update.ProductTitles
        $classif = $Update.Update.UpdateClassificationTitle
        $date = $Update.Update.CreationDate
        $UpdatePSO = New-Object PSCustomObject
		$UpdatePSO | Add-Member -Type NoteProperty -Name "Title" -Value $title
        $UpdatePSO | Add-Member -Type NoteProperty -Name "KB" -Value $kbnumber
		$UpdatePSO | Add-Member -Type NoteProperty -Name "Product" -Value $product
		$UpdatePSO | Add-Member -Type NoteProperty -Name "Class" -Value $classif
		$UpdatePSO | Add-Member -Type NoteProperty -Name "Date" -Value $date		
		$output+=$UpdatePSO
    }
}
$output | Export-CSV wsus-export-unapproved-failed.csv
Write-Host "Done."

J’ai choisi une séparation des colonnes avec un point-virgule car il y a des virgules dans les titres de certaines mises à jour ; il faudra donc veiller à bien spécifier que le point-virgule est le séparateur lors de l’ouverture du fichier CSV dans Excel. Ensuite, d’autres filtres sont possibles dans le tableur, on pourra donc exclure les mises à jour qui ne sont pas de sécurité par exemple.

Ce script, plutôt adapté à mon cas, peut être facilement modifié pour coller aux filtres que vous souhaitez appliquer, soit dans la requête WSUS de base, soit dans le foreach traité juste après.

Powershell : recyclage de pool WSUS à distance

J’avais déjà abordé la question de la consommation de RAM de WSUS à travers son pool applicatif IIS nommé WsusPool dans cet article ; j’ai décidé d’en faire un script Powershell afin de déclencher un recyclage du pool à distance.

Ce script va requêter le serveur via WinRM pour obtenir les informations concernant l’usage de la mémoire vive physique, et sur confirmation, déclencher à distance un recyclage du pool WsusPool.

function recycle{
Write-Host "Trying to start recycling in 5 seconds. Script will automatically end when recycling has successfully been initiated."
Start-Sleep 5
Invoke-Command -ComputerName $iishost -ScriptBlock { Restart-WebAppPool WsusPool }
}

Write-Host "WSUS IIS Application Pool Recycler"
Write-Host "=================================="
Write-Host ""
$iishost = Read-Host "Server to recycle the pool for ?"
$hostdetails = Get-Ciminstance Win32_operatingsystem -ComputerName $iishost
$hostramtotal = $hostdetails.TotalVisibleMemorySize
$hostramused = $hostdetails.TotalVisibleMemorySize - $hostdetails.FreePhysicalMemory
$hostramperc = [math]::Round(($hostramused/$hostramtotal)*100,0)
$hostramtotal = [math]::Round($hostdetails.TotalVisibleMemorySize/1048576,0)
Write-Host "% RAM used: $hostramperc"
Write-Host "Server $iishost has $hostramtotal GB total memory."
$confirm = Read-Host "Please confirm you wish to recycle the WsusPool IIS Application Pool on $iishost (yes)"
if ($confirm -eq "yes") { recycle }
else { Write-Host "Bye." ; break }

Au final, il est possible d’utiliser ce script pour n’importe quel pool car la commande Restart-WebAppPool est liée à IIS et pas spécialement à WSUS.

Migration de serveur DHCP sous Windows Server 2012 R2

Afin de remplacer un serveur DHCP physique défaillant, j’ai monté un nouveau serveur DHCP basé sur une machine virtuelle. Grâce à Powershell, on peut s’occuper de la migration des données propres au serveur DHCP (paramètres, plages, baux…) en 2 coups de cuillère à pot.

Sur l’ancien serveur, on exporte les données :

Export-DhcpServer –ComputerName dhcp-srv -Leases -File C:\dhcp-mig\DhcpSrv-Export.xml -verbose

Puis on importe sur le nouveau serveur ce fichier XML ; à noter que le paramètre -BackupPath permet de spécifier un emplacement où Powershell va sauvegarder la configuration avant importation :


Si jamais l’importation renvoie une erreur « There are no more endpoints available« , il faut alors passer en valeur du paramètre ComputerName le nom NetBIOS de la machine et non son nom DNS (p. ex. : dhcp-srv01 et non dhcp-srv01.domain.com). Pour plus d’informations, vous pouvez consulter ce lien.

Ensuite, pour vérifier que tout est bien importé, en plus d’un contrôle visuel pour les scopes et réservations, cette instruction permet de compter le nombre d’enregistrements : si ils sont identiques avant l’export et après l’importation, cela veut dire que tout s’est bien déroulé (attention, il est possible d’obtenir tout de même une valeur différente si des baux ont expiré depuis l’importation sur le nouveau serveur) :

(Get-DhcpServerv4Scope -Computername dhcp-srv-new | Get-DhcpServerv4Lease -Computername dhcp-srv-new).Count

Vous pouvez trouver tous les cmdlets Powershell propres à DHCP sur le TechNet.