functions/public/Invoke-ForEachParallelProxy.ps1
|
<#
.SYNOPSIS Executes a script block in parallel across multiple input objects with variable management. .DESCRIPTION This function wraps ForEach-Object -Parallel to provide enhanced variable importing capabilities and easier parallel execution management. It allows selective importing of user variables into the parallel context while excluding system and cmdlet-binding variables. The input object is available as $_ within the script block, and parallel execution is controlled via ThrottleLimit, TimeoutSeconds, and optional job execution. .PARAMETER InputObject The object(s) to iterate through in parallel. Accepts arrays or pipeline input. .PARAMETER ScriptBlock The script block to execute for each input object. The current object is available as $_. .PARAMETER ThrottleLimit The maximum number of parallel threads to execute simultaneously. Default value is 5. Increase for more parallelism on systems with more cores. .PARAMETER ImportUserVariables Switch to enable importing current session variables into the parallel execution context. By default, only necessary variables are imported to minimize context overhead. .PARAMETER IncludeUserVariableName Specify an array of variable names to include when ImportUserVariables is enabled. If specified, only these variables will be imported (whitelist mode). .PARAMETER ExcludeUserVariableName Specify an array of variable names to exclude from import when ImportUserVariables is enabled. Works in conjunction with default exclusions (blacklist mode). .PARAMETER TimeoutSeconds The timeout in seconds for each parallel operation. Default 0 (no timeout). Ignored if AsJob is specified. .PARAMETER AsJob Switch to return the operation as a background job instead of waiting for completion. .PARAMETER UseNewRunspace Switch to use a new runspace for each parallel iteration. .PARAMETER Confirm Switch to prompt for confirmation before executing the parallel operation. .EXAMPLE PS> 1..10 | Invoke-ForEachParallelProxy -ScriptBlock { $_ * 2 } -ThrottleLimit 5 Multiplies numbers 1-10 by 2 in parallel with 5 concurrent threads. .EXAMPLE PS> $data = @("file1.txt", "file2.txt", "file3.txt") PS> $data | Invoke-ForEachParallelProxy -ScriptBlock { PS> Get-Content $_ | Measure-Object -Line PS> } -ImportUserVariables Processes multiple files in parallel with access to current session variables. .NOTES Variables are imported intelligently, excluding system variables and cmdlet-binding parameters to reduce context overhead. Use IncludeUserVariableName or ExcludeUserVariableName to fine-tune which variables are passed to parallel contexts. .LINK ForEach-Object Invoke-AZParallelProxy func_GetDefaultExcludeVariables #> function Invoke-ForEachParallelProxy { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [PSObject]$InputObject, [Parameter(Mandatory = $true)] [ScriptBlock]$ScriptBlock, [Parameter(Mandatory = $false)] [Int]$ThrottleLimit = 5, [Parameter(Mandatory = $false)] [Switch]$ImportUserVariables, [Parameter(Mandatory = $false)] [string[]] $IncludeUserVariableName, [Parameter(Mandatory = $false)] [string[]] $ExcludeUserVariableName, [Parameter(Mandatory = $false)] [int]$TimeoutSeconds = 0, [Parameter(Mandatory = $false)] [Switch]$AsJob, [Parameter(Mandatory = $false)] [Switch]$UseNewRunspace, [Parameter(Mandatory = $false)] [Switch]$Confirm ) $combinedScriptBlockString = '' # Get User Variables to Import into Parallel scriptblock if ($ImportUserVariables) { if ($IncludeUserVariableName) { $UserVariables = Get-Variable | where-object { $IncludeUserVariableName -contains $_.Name } Write-Verbose "Including variables $( ($IncludeUserVariableName | Sort-Object ) -join ", ")`n" } else { $VariablesToExclude = func_GetDefaultExcludeVariables # Get Excluded variable names from parameter and add to $VariablesToExclude $VariablesToExclude += $ExcludeUserVariableName Write-Verbose "Excluding variables $( ($VariablesToExclude | Sort-Object ) -join ", ")`n" $UserVariables = @( Get-Variable | Where-Object { -not ($VariablesToExclude -contains $_.Name) } ) Write-Verbose "Found variables to import: $( ($UserVariables | Select-Object -expandproperty Name | Sort-Object ) -join ", " | Out-String).`n" } $ImportedVariablesScriptBlock = { $vars = $Using:UserVariables $vars | ForEach-Object { $Variable = $_ $varcheck = Get-Variable | where-object { $_.Name -eq $Variable.Name } if ($varcheck) { Write-Verbose "Variable $($Variable.Name) already exists with value $($varcheck.Value) and will be skipped." } else { Write-Verbose "Importing variable $($Variable.Name) with value $($Variable.Value)" Set-Variable -Name $Variable.Name -Value $Variable.Value -Scope Global } } } $combinedScriptBlockString += $ImportedVariablesScriptBlock.ToString() + "`n" } $combinedScriptBlockString += $ScriptBlock.ToString() + "`n" $scriptBlockCombined = [scriptblock]::Create($combinedScriptBlockString) $params = @{ Parallel = $scriptBlockCombined ThrottleLimit = $ThrottleLimit UseNewRunspace = $UseNewRunspace Confirm = $Confirm } if ($AsJob -eq $true) { $params.Add('AsJob', $AsJob) } else { $params.Add('TimeoutSeconds', $TimeoutSeconds) } $InputObject | ForEach-Object @params } |