Foreach-Object -Parallel

Iain Barnetson 106 Reputation points
2020-08-31T16:17:14.713+00:00

I want to run a Foreach-Object in parallel with the invoke-command passed having a scriptblock that references a function.

$Workload += Query-SqlData -SqlServer $SqlServer  -Database master -Query $Tsql | Select Instance, Database
$Workload | ForEach-Object -Parallel {
    $ComputerName  = $($_.Instance).Split('\')[0]
    $SqlServer = $($_.Instance)
    $Database = $($_.Database)
    Invoke-Command -ComputerName $ComputerName -AsJob -JobName $Database -ScriptBlock ${Function:Start-UpdateStatistics} `
    -ArgumentList $SqlServer ,$Database
}

But it fails with:
Cannot validate argument on parameter 'ScriptBlock'. The argument is null

When I run the Invoke-Command directly, it runs as expected.

    Invoke-Command -ComputerName $ComputerName -AsJob -JobName $Database -ScriptBlock ${Function:Start-UpdateStatistics} `
    -ArgumentList $SqlServer ,$Database

How can i get this to work in a Foreach-Object parallel ?

Windows Server PowerShell
Windows Server PowerShell
Windows Server: A family of Microsoft server operating systems that support enterprise-level management, data storage, applications, and communications.PowerShell: A family of Microsoft task automation and configuration management frameworks consisting of a command-line shell and associated scripting language.
4,627 questions
{count} votes

1 answer

Sort by: Most helpful
  1. js2010 171 Reputation points
    2020-08-31T18:15:37.623+00:00

    You're running a runspace inside a runspace. You would need the using: scope to access a variable inside the foreach script block.

    $a = 1
    foreach-object -parallel { $using:a }
    

    But invoke-command with multiple computers is already running in parallel, so you don't need the foreach -parallel.

    invoke-command computer1,computer2,computer3 { sleep 10; "$env:computername done" }