I have several thousand computers to backup the Security event logs to a server's share. The environment is very dynamic, hence the need to automate this.
I've been working on a script which creates a hash wherein each key is a sequence and the value for each key is N number of computers. I'm passing the keys and values to another script which will run n number of jobs to backup the logs; n will depend on how many machines I can include in each job and still process the backups efficiently.
Script 1 has this block:
foreach ($key in ($arrayAll.Keys | Sort-Object)) {
Job-EvtLog.ps1 $key @($data)
}
Script 2 has:
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
}
I'm testing this by trying to write the array of computers to a file, hence the Add-Content
.
I'm obviously doing something wrong creating the scriptblock. Get-Job | %{$_.Command}
displays:
foreach ($d in my_List_of_Hostnames) {Add-Content -Path myCorrectpath -Value $d}
Nothing is being written to myCorrectPath.
If I write:
... -Value `$d}")
toward the end of the scriptblock, the display shows the last hostname from the list of hostnames.
How do write the scriptblock such that it will iterate thru the array of hostnames in a scriptblock to process each element in one job?
There are situations where creating a scriptblock from a string makes sense. Yours is not one of them.
In your code the string
"foreach (`$d in $MyComputers) {Add-Content -Path $somewhere -Value `$d}"
should be expanded to a statement like this (assuming arbitrary sample values for $MyComputers
and $somewhere
):
foreach ($d in A B C) {Add-Content -Path C:\some\folder -Value $d}
However, A B C
is not a valid list, meaning that PowerShell would try to invoke A
as a command, so your loop should produce an error like this:
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.
Did you verify by collecting the job output via Receive-Job
?
Create and invoke the scriptblock like this:
$jobCommand = {
Param($path, $computers)
foreach ($d in $computers) {
Add-Content -Path $path -Value $d
}
}
Start-Job -Name $key -ScriptBlock $jobCommand -Args $somewhere, $MyComputers
and the code should do what you want.
Make sure $somewhere
and $MyComputers
actually have the correct values.