Powershell : listing et filtre des tâches planifiées sur de multiples serveurs

Ayant pu enfin appliquer par GPO un traitement que j'effectuais par script appelé par une tâche planifiée quotidiennement, j'ai dû procéder au listing complet des serveurs sur lesquels cette tâche était créée afin de pouvoir procéder à sa suppression. Ne pouvant pas me connecter un à un sur chaque machine pour vérifier la présence ou non, j'ai dû concevoir un script me permettant de lister les tâches planifiées qui portent mon compte d'utilisateur en auteur sur tout un scope de serveurs.

Voici le snippet que j'ai écrit :

$complist = Get-AdComputer -filter * -SearchBase "OU=SERVERS,DC=DUNDERMIFFLIN,DC=local"
foreach ($comp in $complist) {
Write-Host "`r`nServer:"$comp.DNSHostName
Invoke-Command -ComputerName $comp.DNSHostName -ScriptBlock { Get-ScheduledTask | Where-Object { $_.Author -eq "DUNDERMIFFLIN\mscott" } }
}

Ce script renvoie donc toutes les tâches planifiées que l'utilisateur mscott a créé sur chacun des serveurs présents dans la liste retournée par la requête AD. Il est possible de moduler ce que l'on souhaite obtenir en changeant le filtre ou le chemin LDAP dans la requête Get-AdComputer, sans oublier les propriétés des tâches planifiées dans la boucle Where-Object.

A noter que Get-ScheduledTask ne fonctionne qu'à partir de Windows Server 2012. Si jamais l'instruction Invoke-Command renvoie un message d'erreur propre à WinRM et que le contenu de l'instruction fonctionne en local, il vous faut activer l'administration Powershell à distance grâce à la commande Enable-PSremoting.

Powershell : déploiement d'un script et création de tâche planifiée, sur machine distante

Sous ce titre un peu barbare, je vais partager un script que j'ai brodé aujourd'hui. En local sur ma station, j'utilisais un script Powershell me permettant de fermer des sessions RDP simplement déconnectées (que j'ai d'ailleurs publié dans cet article 😉). Seulement, il a été décidé de le modifier de manière à ce que le script ne demande plus un nom de machine particulière, mais de simplement s'occuper de la machine sur laquelle il est exécuté. En contrepartie, l'idée était de le déployer sur tous les serveurs, afin de pouvoir l'appeler via une tâche planifiée de manière à ce que tous les jours les sessions RDP inactives soient shuntées.

Le script ci-dessous va donc effectuer les tâches suivantes :

  • demander un nom de serveur
  • créer un répertoire sur le disque local C:
  • copier le script dans le répertoire fraîchement créé
  • créer une tâche planifiée, exécutée par l'utilisateur SYSTEM, avec une élévation de droits, qui va donc appeler le script qui a été copié.

Plusieurs choses :

  • Les instructions propres au planificateur de tâches ne fonctionnent qu'à partir de Windows 2012 R2 ou 8.1, indépendamment de la version de PS.
  • J'ai utilisé les partages administratifs au lieu d'un PS-Session pour la copie car un Copy-Item -ToSession nécessite PowerShell V5, or mon environnement est hybride V4 et V5 et je ne peux pas tout déployer directement depuis un hôte en V5.
  • Les commandlets du planificateur de tâches ne fonctionnent qu'en local, il faut donc les appeler sur le système distant via Invoke-Command.
$RemoteServer = Read-Host "Destination Server to install script and create scheduled task ?"
$ScriptDir = "\\"+$RemoteServer+"\c$\"
New-Item -Path $ScriptDir -Name "Scripts" -ItemType "directory"
$FinalDest = "\\"+$RemoteServer+"\c$\Scripts"
Copy-Item "script.ps1" -Destination $FinalDest -Force
if ($?){ Write-Host "Copy successful." }
else { Write-Host "Copy failed." ; break }
Invoke-Command -ComputerName $RemoteServer -ScriptBlock {
$TaskDetails = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$TaskAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "C:\Scripts\script.ps1"
$TaskSched = New-ScheduledTaskTrigger -Daily -At 4am
$TaskName = "AutoDisconnectSession"
Register-ScheduledTask -Action $TaskAction -Principal $TaskDetails -Trigger $TaskSched -TaskName $TaskName }
if ($?) { Write-Host "Task successfully created." }
else { "There was an error creating the task." }