RamblingCookieMonster / Invoke-Parallel

Speed up PowerShell with simplified multithreading
MIT License
384 stars 88 forks source link

Get-RunspaceData error: Collection was modified; enumeration operation may not execute #52

Open janegilring opened 6 years ago

janegilring commented 6 years ago

I am leveraging Invoke-Parallel to process VM actions in parallel in an Azure Automation runbook:

        $AzureRMVMs | Invoke-Parallel -ScriptBlock {

            $ARMVM = $PSItem

            $VMStatus = $ARMVM | Get-AzureRmVM -Status | Select-Object Name, @{n = 'PowerState'; e = {($PSItem.Statuses | Where-Object Code -Like "*PowerState*").DisplayStatus}}

            switch ($using:VMAction) {

                'Start' {                        

                    if ($VMStatus.PowerState -ne 'VM running') {

                        Write-Output "VM $($ARMVM.Name) is not running - starting"

                        $ARMVM | Start-AzureRmVM

                    } else {

                        Write-Output "VM $($ARMVM.Name) is already running - no action triggered"

                    }

                }
                'Stop' {

                    if ($VMStatus.PowerState -eq 'VM running') {

                        Write-Output "VM $($ARMVM.Name) is running - stopping"

                        $ARMVM | Stop-AzureRmVM -Force

                    } else {

                        Write-Output "VM $($ARMVM.Name) is already stopped - no action triggered"

                    }

                }
                'Default' {Write-Output "VM Action $($using:VMAction) not defined in runbook, no action taken"}

            }

        } -RunspaceTimeout 300 -NoCloseOnTimeout

This works as expected, however, the following error is generated in the error stream: Get-RunspaceData : Collection was modified; enumeration operation may not execute. At Invoke-Parallell 542 char:13

Any idea what might be causing this?

vors commented 6 years ago

Nice catch! Indeed there is a collection modification inside a foreach loop The simplified version of this code is:

Foreach($runspace in $runspaces) {
...
                    $temphash = $runspaces.clone()
                    $temphash | Where-Object { $_.runspace -eq $Null } | ForEach-Object {
                        $Runspaces.remove($_)
                    }
...
}

https://github.com/RamblingCookieMonster/Invoke-Parallel/blob/master/Invoke-Parallel/Invoke-Parallel.ps1#L325-L328

UPD: nevermind, it happens outside of this loop, it should be something else...