Powershell : clôture d'une sélection de processus

Certaines applications appelées par un ordonnanceur ou des scripts peuvent laisser un processus ouvert sur le système lorsqu'elles ne sont plus utilisées. Ayant été confronté à ce cas d'une application gardant son driver ODBC en processus zombie lorsque la transaction est terminée, j'ai développé un script Powershell qui est appelé en tâche planifiée qui récupère la liste des processus ayant le nom correspondant et qui les tue automatiquement.

$process = Get-Process | Where-Object { $_.ProcessName -like "iexplore" }
foreach($proc in $process){
Stop-Process $proc.Id
}

Il suffit simplement de mettre le nom du processus récalcitrant ou bien de retravailler le script pour éventuellement faire passer un nom en paramètre pour une exécution interactive.

Powershell : automatisation de la création d'un répertoire partagé DFS

J'ai développé un script Powershell permettant d'automatiser tout le process de création d'un répertoire partagé et son ajout à un namespace DFS.

Ce script, prenant en paramètre le nom du partage, va réaliser les opérations suivantes :

  • Création d'un répertoire sur le disque et création d'un partage SMB sur ce même répertoire ;
  • Création et peuplement de groupes AD qui permettront de définir les droits en lecture et écriture ;
  • Ajout des ACL sur le partage ;
  • Ajout du répertoire dans le namespace DFS.

Il sera nécessaire, avant exécution du script, d'éventuellement modifier les variables déclarées en début de code afin de les adapter à l'environnement d'exécution ou au process habituellement suivi.

param([Parameter(Mandatory=$true)][string]$ShareName)
$path = "D:\DFS"
$dfspath = "\\dundermifflin.com\DFS"
$srvname = "PWFILE01"
$ou = "OU=DFS,OU=Access_Groups,DC=dundermifflin,DC=com"
$readarray = @()
$writearray = @()
$readgroup = "DFS-$ShareName-RX"
$writegroup = "DFS-$ShareName-W"
New-Item -path $path -name $ShareName -ItemType "Directory" -ErrorAction Stop | Out-Null
New-ADGroup -Name $readgroup -GroupCategory Security -GroupScope DomainLocal -Path $ou -Description "\\dundermifflin.com\DFS\$ShareName - Read Only" -ErrorAction Stop
New-ADGroup -Name $writegroup -GroupCategory Security -GroupScope DomainLocal -Path $ou -Description "\\dundermifflin.com\DFS\$ShareName - Write" -ErrorAction Stop
New-SmbShare -Name $ShareName -Path "$path\$ShareName" -FullAccess "BUILTIN\Administrators" -ReadAccess $readgroup -ChangeAccess $writegroup -ErrorAction Stop
Write-Host "You will be prompted the usernames to add to the read-only access group. Please input only one user at a time. When you are done, leave the field empty and press enter."
do {
$readacc = Read-Host "Account name to add to the READ group"
if($readacc -ne "") {$readarray+=$readacc}
}
while($readacc -ne "")
Write-Host "Now you will be prompted the usernames to add to the modification group. Please input only one user at a time. When you are done, leave the field empty and press enter."
do {
$writeacc = Read-Host "Account name to add to the WRITE group"
if($writeacc -ne "") {$writearray+=$writeacc}
}
while($writeacc -ne "")
if($readarray -ne $null) { Add-ADGroupMember -Identity $readgroup -Members $readarray }
if($writearray -ne $null) { Add-ADGroupMember -Identity $writegroup -Members $writearray }
$acl = Get-Acl "$path\$ShareName"
$acl.SetAccessRuleProtection($true,$false)
$readacl = New-Object Security.AccessControl.FileSystemAccessRule("DUNDERMIFFLIN\$readgroup","ReadAndExecute, Synchronize",3,0,"Allow")
$acl.SetAccessRule($readacl)
$writeacl = New-Object Security.AccessControl.FileSystemAccessRule("DUNDERMIFFLIN\$writegroup","Modify, Synchronize",3,0,"Allow")
$acl.SetAccessRule($writeacl)
$sysacl = New-Object Security.AccessControl.FileSystemAccessRule("NT AUTHORITY\System","FullControl",3,0,"Allow")
$acl.SetAccessRule($sysacl)
$admacl = New-Object Security.AccessControl.FileSystemAccessRule("BUILTIN\Administrators","FullControl",3,0,"Allow")
$acl.SetAccessRule($admacl)
$acl | Set-Acl
New-DfsnFolder -path "$dfspath\$ShareName" -Target "\\$srvname\$ShareName"

Une version commentée du script est disponible en téléchargement.

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){
[xml]$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
[xml]$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.

Access Denied en chaîne sur un FTP porté par IIS

J'ai mis en place un serveur FTP porté par un serveur IIS installé sur un Windows Server 2016. Ce serveur FTP autorise un compte de service sans droits particuliers à écrire sur un répertoire virtuel configuré dans IIS.

Ce compte de service est bien renseigné pour avoir les droits sur le répertoire dans lequel il est censé écrire, et ses droits Read, Write sont bien portés à la fois sur la racine FTP ftproot et sur le répertoire virtuel. Cependant, à la connexion et ce peu importe le client FTP, j'obtenais un simple Access Denied après la transaction d'authentification et l'acceptation du certificat SSL. Après avoir essayé avec mon compte d'administration ayant exactement les mêmes privilèges sur la machine, cela fonctionnait. Le problème est donc lié au compte en lui-même.

Un petit tour dans le fichier de configuration de IIS disponible dans C:\Windows\System32\inetsrv\config\applicationHost.config (comme expliqué dans cet article) me donne rien de plus : les balises sont bien renseignées et le compte en question a bien les droits de connexion.


J'essaye alors d'ajouter le compte en tant qu'administrateur local pour voir si cela fait la différence, et c'est alors qu'un détail me saute aux yeux : dans la fenêtre du groupe des administrateurs locaux, le compte apparaît avec son appellation pré-Windows 2000. Sur cet exemple, le compte testcomptedeserviceftp@mondomaine.com est renseigné avec son nom pré-Windows 2000 MONDOMAINE\testcomptedeservicef :


On peut vérifier dans l'ActiveDirectory les deux noms de connexion :

La console ActiveDirectory Users and Computers permet de vérifier les deux logins d'un utilisateur.

Dans IIS, en remplaçant le nom de connexion usuel par le nom pré-Windows 2000, j'ai pu me connecter.

Il est donc nécessaire d'attribuer les privilèges en utilisant les noms pré-Windows 2000.

En effet, si le nom de mon compte d'administration n'était pas tronqué car identique qu'il soit pré-Windows 2000 ou non, ce n'était pas le cas pour mon compte de service (identifiant trop long). Je tentais donc de me connecter avec un compte inconnu de IIS ; j'ai donc appris aujourd'hui que ce dernier gère les privilèges FTP avec les noms de connexion pré-Windows 2000, ce qui m'a pris une petite heure à réaliser.

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.

Vous pouvez télécharger le script en cliquant sur ce lien.