リモートシステム上のすべてのスケジュールされたタスクを一覧表示し、各タスクの実行に使用されるユーザーアカウントを含むPowerShellスクリプトを記述したいと思います。
ローカルシステムはWindows 7とPowerShell 3.0を実行しています。リモートシステムの範囲はServer 2003から2008 R2で、PowerShellのバージョンは2.0から3.0です。
このタスクに使用できるPowerShellコマンドまたは関数は何ですか?
ようやく自分のニーズに合ったスクリプトを書きました。このスクリプトは、ADにリストされているすべてのサーバーを「スキャン」し、c:\ Windows\System32\tasksフォルダーでxmlファイルを検索します。次に、各ファイルのUserID xmlノードの値を最終的なCSVファイルに書き込みます。
まだ完璧ではありませんが、すべてのサーバーのすべてのタスクを一覧表示し、それらを実行するために使用されたユーザーアカウントをログに記録するために完全に機能しています。
<#
.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"
}
}
}
出力は、次のように、デスクトップで生成されたコンマ区切りファイルです。
> SRV028,CCleanerSkipUAC,administrator
> SRV029,GoogleUpdateTaskMachineCore,System
> SRV030,GoogleUpdateTaskMachineUA,System
> SRV021,BackupMailboxes,DOMAIN\administrator
> SRV021,Compress&Archive,DOMAIN\sysScheduler
Ob1lanが投稿したスクリプトの修正版を共有したいと思いました。変更により、ネストされたフォルダー内のタスクを検索し、タスクのステータスと元のタスクに含まれる詳細を一覧表示できます。
$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
[〜#〜]注[〜#〜]:サーバーが多数ある場合、実行に時間がかかります。並列で実行したい場合は、呼び出し並列スクリプト(Google it)を使用できます。これは大幅に高速化します。
. \\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
出力例:
このコマンドを使用して、すべてのタスクを一覧表示しました。
Invoke-Command -ComputerName "computername" -Credential Get-Credential {schtasks.exe}
注意:警告:次のような-literalpathを使用することをお勧めします。
$TaskInfo = [xml](Get-Content -literalpath $AbsolutePath)
またはget-content
は、タスク名またはフォルダー名にワイルドカードや正規表現の文字が含まれている場合は何も返しません。
はい、Powershellはリテラル文字列だけでなく、文字列型変数の内容も解釈するようです。