Private/Invoke-VenafiParallel.ps1
function Invoke-VenafiParallel { <# .SYNOPSIS Helper function to execute a scriptblock in parallel .DESCRIPTION This is a wrapper around ForEach-Object -Parallel .PARAMETER InputObject List of items to iterate over .PARAMETER ScriptBlock Scriptblock to execute against the list of items .PARAMETER ThrottleLimit Max number of threads at once. The default is 20. .PARAMETER ProgressTitle Message displayed on the progress bar .PARAMETER NoProgress Do not display the progress bar .PARAMETER VenafiSession Authentication for the function. .NOTES PowerShell v7+ is supported .EXAMPLE Invoke-VenafiParallel -InputObject $myObjects -ScriptBlock { Do-Something $PSItem } Execute in parallel. Reference each item in the scriptblock as $PSItem or $_. .EXAMPLE Invoke-VenafiParallel -InputObject $myObjects -ScriptBlock { Do-Something $PSItem } -ThrottleLimit 5 Only run 5 threads at a time instead of the default of 20. .EXAMPLE Invoke-VenafiParallel -InputObject $myObjects -ScriptBlock { Do-Something $PSItem } -NoProgress Execute in parallel with no progress bar. #> [CmdletBinding()] param ( [Parameter(Mandatory)] [psobject] $InputObject, [Parameter(Mandatory)] [scriptblock] $ScriptBlock, [Parameter()] [int] $ThrottleLimit = 20, [Parameter()] [string] $ProgressTitle = 'Performing action', [Parameter()] [switch] $NoProgress, [Parameter(Mandatory)] [psobject] $VenafiSession ) begin { if ($PSVersionTable.PSVersion.Major -lt 7) { throw 'PowerShell v7 or greater is required for this function' } if ( -not $NoProgress ) { Write-Progress -Activity $ProgressTitle -Status "Initializing..." } } process { } end { $thisDir = $PSScriptRoot $starterSb = { # need to import module until https://github.com/PowerShell/PowerShell/issues/12240 is complete # import via path instead of just module name to support development work Import-Module (Join-Path -Path (Split-Path $using:thisDir -Parent) -ChildPath 'VenafiPS.psd1') -Force # grab the api key as passing VenafiSession as is causes powershell to hang $VenafiSession = if ( ($using:VenafiSession).GetType().Name -eq 'VenafiSession' ) { ($using:VenafiSession).Key.GetNetworkCredential().Password } else { $using:VenafiSession } } $newSb = ([ScriptBlock]::Create($starterSb.ToString() + $ScriptBlock.ToString())) $job = $InputObject | Foreach-Object -AsJob -ThrottleLimit $ThrottleLimit -Parallel $newSb if ( -not $job.ChildJobs ) { return } do { # Sleep a bit to allow the threads to run - adjust as desired. Start-Sleep -Seconds 1 # Determine how many jobs have completed so far. $completedJobsCount = $job.ChildJobs.Where({ $_.State -notin 'NotStarted', 'Running' }).Count # Relay any pending output from the child jobs. $job | Receive-Job if ( -not $NoProgress ) { # Update the progress display. [int] $percent = ($completedJobsCount / $job.ChildJobs.Count) * 100 Write-Progress -Activity $ProgressTitle -Status "$percent% complete" -PercentComplete $percent } } while ($completedJobsCount -lt $job.ChildJobs.Count) } } |