使用多个参数和foreach循环调用PowerShell Start-Job cmdlet非常接近

时间:2017-08-22 21:41:06

标签: powershell start-job scriptblock

我有几千台计算机将安全事件日志备份到服务器的共享。环境非常动态,因此需要自动化。

我一直在创建一个脚本,该脚本创建一个哈希,其中每个键都是一个序列,每个键的值是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}")

在脚本块的末尾,显示屏显示主机名列表中的最后一个主机名。

如何编写scriptblock,使其通过scriptblock中的主机名数组进行迭代,以处理一个作业中的每个元素?

2 个答案:

答案 0 :(得分:1)

好的,让我们从脚本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]
}

答案 1 :(得分:1)

在某些情况下,从字符串创建脚本块是有意义的。你的不是其中之一。

在你的代码中使用字符串

"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'不被识别为cmdlet,函数,脚本文件或可操作程序的名称。检查名称的拼写,或者如果包含路径,请验证路径是否正确,然后重试。

您是否通过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实际上具有正确的值。