Search code examples
powershellpowershell-core

ForEach-Object -Parallel How to use it


I'm starting to use ForEach-Object -Parallel with PowerShell 7. I'm testing following code:

$MyArr = @()
$MyArr = (
    ('v1ne','rgNE'),`
    ('v1we','rgWE')
)

$MyArr | ForEach-Object -Parallel  { 
    Start-AzVM -Name $MyArr[0]  -ResourceGroupName $MyArr[1]
} -ThrottleLimit 10

To start up some virtual machine on azure in different Resource Groups. My idea is to get variable from array or from Azure automation variables. But I don't know how to pass different Resource Group Names in ForEach-Object -Parallel.

Any help is really appreciate.


Solution

  • As Mathias explained in comments, when using ForEach-Object -Parallel, you would need to use $_ (also known as $PSItem) to reference the current object from pipeline (same applies for ForEach-Object). If you want to reference a variable that is not coming from pipeline you would use the $using: keyworkd.

    Example:

    $notFromPipeline = 'Hello'
    
    0..5 | ForEach-Object -Parallel {
        "$using:notFromPipeline $_"
    }
    

    As for, how you could approach your script, I think splatting with $_ seems fit for this, suppose you had a CSV with the VM Names and their corresponding Resource Groups, something like:

    • VMs.csv
    Name,ResourceGroupName
    v1ne,rgNE
    v1we,rgwE
    

    You could do something like this, note, below example is using a function (TestSplat) just to show you how the parameters are bound using splatting with a hash table, in your case, you would replace this function for Start-AzVM.

    First you can create an array of hash tables like this:

    $myParams = Import-Csv ./VMs.csv | ForEach-Object {
        $z = @{}
        foreach($prop in $_.PSObject.Properties) {
            $z[$prop.Name] = $prop.Value
        }
        $z
    }
    

    $myParams would be something like this:

    Name                           Value
    ----                           -----
    Name                           v1ne
    ResourceGroupName              rgNE
    Name                           v1we
    ResourceGroupName              rgwE
    

    The column names of your CSV must match with the Parameter Names of Start-VM (Name and ResourceGroupName).

    Now you can iterate over $myParams using ForEach-Object -Parallel:

    $myParams | ForEach-Object -Parallel  {
        function TestSplat {
            param($Name, $ResourceGroupName)
            Write-Host "Name: $Name - ResourceGroup: $ResourceGroupName"
        }
    
        TestSplat @_
    } -ThrottleLimit 10
    

    Which should result in:

    Name: v1ne - ResourceGroup: rgNE
    Name: v1we - ResourceGroup: rgwE