使用多个参数和 foreach 循环调用 PowerShell Start-Job cmdlet 非常接近
Calling PowerShell Start-Job cmdlet with multiple parameters and foreach loop is soooo close
我有几千台计算机将安全事件日志备份到服务器的共享中。环境非常动态,因此需要自动化。
我一直在编写一个创建散列的脚本,其中每个键都是一个序列,每个键的值是 N 台计算机。我将键和值传递给另一个脚本,该脚本将 运行 n 个作业来备份日志; n 将取决于我可以在每个作业中包括多少台机器,并且仍然有效地处理备份。
脚本 1 有这个块:
foreach ($key in ($arrayAll.Keys | Sort-Object)) {
Job-EvtLog.ps1 $key @($data)
}
脚本 2 有:
Param(
[Parameter[Mandatory=$true, ValueFromPipeline=$true)]
[string[]] $Key,
[Parameter[Mandatory=$true, ValueFromPipeline=$true)]
[Array[]] $Computers
)
function job_process($key) {
#...stuff...including casting the @($Computers) to the array: $MyComputers
$jobCommand = [ScriptBlock]::Create("foreach(`$d in $MyComputers) {Add-Content -Path $somewhere -Value `$d}")
Start-Job -Name $key $jobCommand -Args $somewhere $MyComputers
}
我正在通过尝试将计算机数组写入文件来对此进行测试,因此 Add-Content
。
我显然在创建脚本块时做错了什么。 Get-Job | %{$_.Command}
显示:
foreach ($d in my_List_of_Hostnames) {Add-Content -Path myCorrectpath -Value $d}
没有任何内容写入 myCorrectPath。
如果我写:
... -Value `$d}")
接近脚本块的末尾,显示屏显示主机名列表中的最后一个主机名。
如何编写脚本块,使其遍历脚本块中的主机名数组以处理一个作业中的每个元素?
好的,让我们从脚本 2 的顶部开始:参数
这是字符串的类型转换:[string]
这是字符串数组的类型转换:[string[]]
您是否期望 $key
是一个字符串数组,或者只是一个字符串,因为您只将一个字符串传递给它。同样的概念适用于 $Computers
期望数组的数组。
此外,您有两个东西从管道中接受它们的值,这只会让事情变得混乱。也许相反,您应该将其排除在外,或者将其更改为 ValueFromPipelineByPropertyName
,如果您要将内容传递给其他内容,这是一个很棒的选择。
接下来,您有一个带有 1 个参数的函数。在该函数中,您使用多个变量,并以困难的方式制作脚本块,这似乎并不明智。我认为可能更好的方法是:
Param(
[Parameter(Mandatory)]
[string] $Key,
[Parameter(Mandatory)]
[string[]] $Computers)
#...stuff...including casting the @($Computers) to the array: $MyComputers
$jobCommand = {
Param($JobPath,$JobComputers)
foreach($d in $JobComputers) {add-content -Path $JobPath -Value $d}
}
start-job -name $key -scriptblock $jobCommand -argumentlist $somewhere $MyComputers
那么你可以这样称呼它:
foreach ($key in ($arrayAll.Keys | Sort-Object)) {
Job-EvtLog.ps1 -Key $key -Computers $arrayAll[$key]
}
在某些情况下,从字符串创建脚本块是有意义的。你的不是其中之一。
在您的代码中,字符串
"foreach (`$d in $MyComputers) {Add-Content -Path $somewhere -Value `$d}"
应该扩展为这样的语句(假设 $MyComputers
和 $somewhere
的任意样本值):
foreach ($d in A B C) {Add-Content -Path C:\some\folder -Value $d}
但是,A B C
不是有效列表,这意味着 PowerShell 会尝试将 A
作为命令调用,因此您的循环应该会产生如下错误:
A : The term 'A' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
您是否通过 Receive-Job
收集作业输出进行了验证?
像这样创建和调用脚本块:
$jobCommand = {
Param($path, $computers)
foreach ($d in $computers) {
Add-Content -Path $path -Value $d
}
}
Start-Job -Name $key -ScriptBlock $jobCommand -Args $somewhere, $MyComputers
并且代码应该可以满足您的要求。
确保 $somewhere
和 $MyComputers
确实具有正确的值。
我有几千台计算机将安全事件日志备份到服务器的共享中。环境非常动态,因此需要自动化。
我一直在编写一个创建散列的脚本,其中每个键都是一个序列,每个键的值是 N 台计算机。我将键和值传递给另一个脚本,该脚本将 运行 n 个作业来备份日志; n 将取决于我可以在每个作业中包括多少台机器,并且仍然有效地处理备份。
脚本 1 有这个块:
foreach ($key in ($arrayAll.Keys | Sort-Object)) {
Job-EvtLog.ps1 $key @($data)
}
脚本 2 有:
Param(
[Parameter[Mandatory=$true, ValueFromPipeline=$true)]
[string[]] $Key,
[Parameter[Mandatory=$true, ValueFromPipeline=$true)]
[Array[]] $Computers
)
function job_process($key) {
#...stuff...including casting the @($Computers) to the array: $MyComputers
$jobCommand = [ScriptBlock]::Create("foreach(`$d in $MyComputers) {Add-Content -Path $somewhere -Value `$d}")
Start-Job -Name $key $jobCommand -Args $somewhere $MyComputers
}
我正在通过尝试将计算机数组写入文件来对此进行测试,因此 Add-Content
。
我显然在创建脚本块时做错了什么。 Get-Job | %{$_.Command}
显示:
foreach ($d in my_List_of_Hostnames) {Add-Content -Path myCorrectpath -Value $d}
没有任何内容写入 myCorrectPath。
如果我写:
... -Value `$d}")
接近脚本块的末尾,显示屏显示主机名列表中的最后一个主机名。
如何编写脚本块,使其遍历脚本块中的主机名数组以处理一个作业中的每个元素?
好的,让我们从脚本 2 的顶部开始:参数
这是字符串的类型转换:[string]
这是字符串数组的类型转换:[string[]]
您是否期望 $key
是一个字符串数组,或者只是一个字符串,因为您只将一个字符串传递给它。同样的概念适用于 $Computers
期望数组的数组。
此外,您有两个东西从管道中接受它们的值,这只会让事情变得混乱。也许相反,您应该将其排除在外,或者将其更改为 ValueFromPipelineByPropertyName
,如果您要将内容传递给其他内容,这是一个很棒的选择。
接下来,您有一个带有 1 个参数的函数。在该函数中,您使用多个变量,并以困难的方式制作脚本块,这似乎并不明智。我认为可能更好的方法是:
Param(
[Parameter(Mandatory)]
[string] $Key,
[Parameter(Mandatory)]
[string[]] $Computers)
#...stuff...including casting the @($Computers) to the array: $MyComputers
$jobCommand = {
Param($JobPath,$JobComputers)
foreach($d in $JobComputers) {add-content -Path $JobPath -Value $d}
}
start-job -name $key -scriptblock $jobCommand -argumentlist $somewhere $MyComputers
那么你可以这样称呼它:
foreach ($key in ($arrayAll.Keys | Sort-Object)) {
Job-EvtLog.ps1 -Key $key -Computers $arrayAll[$key]
}
在某些情况下,从字符串创建脚本块是有意义的。你的不是其中之一。
在您的代码中,字符串
"foreach (`$d in $MyComputers) {Add-Content -Path $somewhere -Value `$d}"
应该扩展为这样的语句(假设 $MyComputers
和 $somewhere
的任意样本值):
foreach ($d in A B C) {Add-Content -Path C:\some\folder -Value $d}
但是,A B C
不是有效列表,这意味着 PowerShell 会尝试将 A
作为命令调用,因此您的循环应该会产生如下错误:
A : The term 'A' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
您是否通过 Receive-Job
收集作业输出进行了验证?
像这样创建和调用脚本块:
$jobCommand = {
Param($path, $computers)
foreach ($d in $computers) {
Add-Content -Path $path -Value $d
}
}
Start-Job -Name $key -ScriptBlock $jobCommand -Args $somewhere, $MyComputers
并且代码应该可以满足您的要求。
确保 $somewhere
和 $MyComputers
确实具有正确的值。