Je souhaite écrire un script PowerShell qui répertorie toutes les tâches planifiées sur des systèmes distants et inclut le compte d'utilisateur qui sera utilisé pour exécuter chaque tâche.
Le système local exécute Windows 7, avec PowerShell 3.0. Les systèmes distants vont de Server 2003 à 2008 R2, avec les versions de PowerShell de 2.0 à 3.0.
Quelles commandes ou fonctions PowerShell puis-je utiliser pour cette tâche?
J'ai finalement écrit un script qui convient à mes besoins. Ce script "analyse" tous les serveurs répertoriés dans AD, en recherchant les fichiers xml dans le dossier c:\Windows\System32\tasks. Ensuite, il écrira la valeur du nœud XML UserID de chaque fichier dans le fichier CSV final.
Pas encore parfait, mais fonctionne parfaitement pour répertorier toutes les tâches de tous les serveurs et consigner le compte d'utilisateur utilisé pour les exécuter.
<#
.Synopsis
PowerShell script to list all Scheduled Tasks and the User ID
.DESCRIPTION
This script scan the content of the c:\Windows\System32\tasks and search the UserID XML value.
The output of the script is a comma-separated log file containing the Computername, Task name, UserID.
#>
Import-Module ActiveDirectory
$VerbosePreference = "continue"
$list = (Get-ADComputer -LDAPFilter "(&(objectcategory=computer)(OperatingSystem=*server*))").Name
Write-Verbose -Message "Trying to query $($list.count) servers found in AD"
$logfilepath = "$home\Desktop\TasksLog.csv"
$ErrorActionPreference = "SilentlyContinue"
foreach ($computername in $list)
{
$path = "\\" + $computername + "\c$\Windows\System32\Tasks"
$tasks = Get-ChildItem -Path $path -File
if ($tasks)
{
Write-Verbose -Message "I found $($tasks.count) tasks for $computername"
}
foreach ($item in $tasks)
{
$AbsolutePath = $path + "\" + $item.Name
$task = [xml] (Get-Content $AbsolutePath)
[STRING]$check = $task.Task.Principals.Principal.UserId
if ($task.Task.Principals.Principal.UserId)
{
Write-Verbose -Message "Writing the log file with values for $computername"
Add-content -path $logfilepath -Value "$computername,$item,$check"
}
}
}
La sortie est un fichier séparé par des virgules généré sur votre bureau, comme celui-ci:
> SRV028,CCleanerSkipUAC,administrator
> SRV029,GoogleUpdateTaskMachineCore,System
> SRV030,GoogleUpdateTaskMachineUA,System
> SRV021,BackupMailboxes,DOMAIN\administrator
> SRV021,Compress&Archive,DOMAIN\sysScheduler
Hey pensait que je partagerais une version modifiée du script posté par Ob1lan. La modification permet de rechercher des tâches dans des dossiers imbriqués et répertorie le statut de la tâche ainsi que les détails inclus dans l'original.
$Computers = (get-adcomputer -filter {operatingsystem -like "*server*"}).name
$ErrorActionPreference = "SilentlyContinue"
$Report = @()
foreach ($Computer in $Computers)
{
if (test-connection $Computer -quiet -count 1)
{
#Computer is online
$path = "\\" + $Computer + "\c$\Windows\System32\Tasks"
$tasks = Get-ChildItem -recurse -Path $path -File
foreach ($task in $tasks)
{
$Details = "" | select ComputerName, Task, User, Enabled, Application
$AbsolutePath = $task.directory.fullname + "\" + $task.Name
$TaskInfo = [xml](Get-Content $AbsolutePath)
$Details.ComputerName = $Computer
$Details.Task = $task.name
$Details.User = $TaskInfo.task.principals.principal.userid
$Details.Enabled = $TaskInfo.task.settings.enabled
$Details.Application = $TaskInfo.task.actions.exec.command
$Details
$Report += $Details
}
}
else
{
#Computer is offline
}
}
$Report | ft
NOTE: Si vous avez plusieurs serveurs, son exécution prendra beaucoup de temps. Si vous souhaitez l'exécuter en parallèle, vous pouvez utiliser le script invoke-parallel (Google it), qui est nettement plus rapide :
. \\server\path\to\invoke-parallel.ps1
$Computers = (get-adcomputer -filter {operatingsystem -like "*server*"}).name
$ErrorActionPreference = "SilentlyContinue"
$Scriptblock =
{
$path = "\\" + $_ + "\c$\Windows\System32\Tasks"
$tasks = Get-ChildItem -recurse -Path $path -File
foreach ($task in $tasks)
{
$Details = "" | select ComputerName, Task, User, Enabled, Application
$AbsolutePath = $task.directory.fullname + "\" + $task.Name
$TaskInfo = [xml](Get-Content $AbsolutePath)
$Details.ComputerName = $_
$Details.Task = $task.name
$Details.User = $TaskInfo.task.principals.principal.userid
$Details.Enabled = $TaskInfo.task.settings.enabled
$Details.Application = $TaskInfo.task.actions.exec.command
$Details
}
}
$Report = invoke-parallel -input $Computers -scriptblock $Scriptblock -throttle 400 -runspacetimeout 30 -nocloseontimeout
$Report | ft
Exemple de résultat :
J'ai utilisé cette commande pour lister toutes les tâches:
Invoke-Command -ComputerName "computername" -Credential Get-Credential {schtasks.exe}