2017-08-22 36 views
0

我有几千台计算机将安全事件日志备份到服务器的共享。环境非常动态,因此需要将其自动化。调用具有多个参数和foreach循环的PowerShell Start-Job cmdlet是如此关闭

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

向脚本块的结束,显示屏将显示从主机名的列表中最后一个主机名。

如何编写脚本块,以便它将遍历脚本块中的主机名数组以处理每个作业中的每个元素?

回答

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实际上具有正确的值。

+0

谢谢;这根据需要工作并解决我的问题。 – GaryG

1

好了,让我们开始在脚本2的顶部:参数

这是字符串类型转换:[string]
这是一个字符串数组类型转换:[string[]]

你期待$key是一个字符串数组,或者只是一个字符串,因为你只传递一个字符串给它。 $Computers也适用于期望数组的数组。

此外,你有两件事从管道接受它们的价值,这只会让事情混淆。也许相反,你应该把它放在外面,或者将它改为ValueFromPipelineByPropertyName,如果你要把东西转移到其他东西上,这是一个非常棒的选择。

接下来,你有一个函数需要1个参数。在这个函数中你使用了几个变量,并且以一种很难的方式创建了一个scriptblock,这看起来并不明智。我觉得可能是一个更好的办法来做到这一点是:

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] 
} 
+0

在我原来的文章中,我留了一条线。 我的电话有这样一行: $ data = $ arrayAll.item($ key)。 我认为这是净效应是类似于你的建议,尽管不够干净。 我按照你的指示改变了param块。 谢谢。 – GaryG