RunspacePoolManager.psm1
function Start-RunspacePool { <# .EXTERNALHELP RunspacePoolManager.psm1-Help.xml #> [CmdletBinding(ConfirmImpact = 'Medium', SupportsShouldProcess = $false)] [alias("Start-RSP")] [OutputType([System.Management.Automation.Runspaces.RunspacePool])] param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [int]$MaxJobs = $env:NUMBER_OF_PROCESSORS, [Parameter(Position = 1)] [ValidateNotNullOrEmpty()] [System.Management.Automation.Runspaces.InitialSessionState]$InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault(), [Parameter(Position = 2)] [ValidateScript({ if ($_ -match '(([0-1][0-9])|([2][0-3])):([0-5][0-9]):([0-5][0-9])') { return $true } else { Write-Warning -Message "The CleanupInterval must be HH:MM:SS." } })] [System.TimeSpan]$CleanupInterval = "00:15:00" ) begin { $functionName = $($MyInvocation.MyCommand).Name Write-Verbose -Message "$functionName`: Entering the begin block." } process { Write-Verbose -Message "$functionName`: Entering the process block." try { Write-Verbose -Message "$functionName`: Starting runspace pool with $MaxJobs max jobs." $return = [runspacefactory]::CreateRunspacePool(1, $MaxJobs, $initialSessionState, $host) $return.CleanupInterval = $CleanupInterval $powerShell = [powershell]::Create() $powerShell.RunspacePool = $return $return.Open() } catch { $exception = "$($_.Exception.GetType().FullName)" $msg = "Unhandled error: $_" Write-Warning -Message $exception Write-Warning -Message $msg } } end { Write-Verbose -Message "$functionName`: Entering the end block." if (-not ([string]::IsNullOrEmpty($return))) { Write-Output $return } } } function Start-RunspacePoolJob { <# .EXTERNALHELP RunspacePoolManager.psm1-Help.xml #> [CmdletBinding(ConfirmImpact = 'Medium', SupportsShouldProcess = $false)] [alias("Start-RSPJob")] param ( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [scriptblock]$ScriptBlock, [Parameter(Mandatory = $true, Position = 1)] [ValidateNotNullOrEmpty()] [System.Management.Automation.Runspaces.RunspacePool]$RunspacePool, [Parameter(Mandatory = $false, Position = 0)] [System.Collections.Hashtable]$HashTable ) begin { $functionName = $($MyInvocation.MyCommand).Name Write-Verbose -Message "$functionName`: Entering the begin block." if ($RunspacePool.IsDisposed) { Write-Error -Message "The runspace pool has been closed." -Category InvalidOperation break } } process { Write-Verbose -Message "$functionName`: Entering the process block." try { Write-Verbose -Message "$functionName`: Processing script block for using variables." #https://github.com/proxb/PoshRSJob/blob/master/PoshRSJob/Public/Start-RSJob.ps1 $usingVariables = @(GetUsingVariables $ScriptBlock) if ($usingVariables.count -gt 0) { Write-Verbose -Message "$functionName`: Using variables were found. Processing script using variables." $usingVar = $usingVariables | Group-Object SubExpression | ForEach-Object { $_.Group | Select-Object -First 1 } #Write-Debug "CommandOrigin: $($MyInvocation.CommandOrigin)" $usingVariableValues = @(foreach ($var in $usingVar) { try { if ($MyInvocation.CommandOrigin -eq 'Runspace') { $value = Get-Variable -Name $Var.SubExpression.VariablePath.UserPath } else { $value = ($PSCmdlet.SessionState.PSVariable.Get($var.SubExpression.VariablePath.UserPath)) if ([string]::IsNullOrEmpty($Value)) { throw 'No value!' } } [pscustomobject]@{ Name = $var.SubExpression.Extent.Text Value = $value.Value NewName = ('$__using_{0}' -f $var.SubExpression.VariablePath.UserPath) NewVarName = ('__using_{0}' -f $var.SubExpression.VariablePath.UserPath) } } catch { throw "The value of the using variable '$($var.SubExpression.Extent.Text)' cannot be retrieved because it has not been set in the local session." } }) #endregion Get Variable Values Write-Verbose -Message ("$functionName`: Found {0} `$Using: variables!" -f $usingVariableValues.count) } if (($UsingVariableValues.Count -gt 0) -or ($HashTable)) { Write-Verbose -Message "$functionName`: Converting script with using variables." $convertScriptParams = @{ ScriptBlock = $ScriptBlock HasParam = ($SBParamVars.Count -ne 0) UsingVariables = $UsingVariables UsingVariableValues = $UsingVariableValues HashTable = $HashTable } $NewScriptBlock = ConvertScript @convertScriptParams } else { $NewScriptBlock = $ScriptBlock } Write-Verbose -Message "$functionName`: running:" Write-Verbose -Message "$functionName`: $($NewScriptBlock | Out-String)" #https://github.com/proxb/PoshRSJob/blob/master/PoshRSJob/Public/Start-RSJob.ps1 Write-Verbose -Message "$functionName`: Build the PowerShell runspace and assign it to the pool." $powerShell = [powershell]::Create() $powerShell.RunspacePool = $RunspacePool $powerShell.AddScript($NewScriptBlock) | Out-Null Write-Verbose "$functionName`: Checking for Using: variables" if ($UsingVariableValues.count -gt 0) { for ($i = 0; $i -lt $UsingVariableValues.count; $i++) { Write-Verbose "$functionName`: Adding Param: $($UsingVariableValues[$i].Name) Value: $($UsingVariableValues[$i].Value)" [void]$powerShell.AddParameter($UsingVariableValues[$i].NewVarName, $UsingVariableValues[$i].Value) } } if ($HashTable) { Write-Verbose "$functionName`: Adding HashTable param to script." [void]$powerShell.AddParameter('HashTable', $HashTable) } $return = $powerShell.BeginInvoke() } catch { $continue = $false $exception = "$($_.Exception.GetType().FullName)" $msg = "Unhandled error: $_" Write-Warning -Message $exception Write-Warning -Message $msg } } end { Write-Verbose -Message "$functionName`: Entering the end block." if ($return) { Write-Output $return } } } function Stop-RunspacePool { <# .EXTERNALHELP RunspacePoolManager.psm1-Help.xml #> [CmdletBinding(ConfirmImpact = 'High', SupportsShouldProcess = $true)] [alias("Stop-RSP")] param ( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [System.Management.Automation.Runspaces.RunspacePool]$RunspacePool, [switch]$Force ) begin { $functionName = $($MyInvocation.MyCommand).Name Write-Verbose -Message "$functionName`: Entering the begin block." } process { Write-Verbose -Message "$functionName`: Entering the process block." try { $msg = 'Running Stop-RunspacePool will terminate all jobs immediately and cancel all pending jobs.' $prompt = 'Do you want to continue?' if (($Force) -or ($PSCmdlet.ShouldProcess($msg, $prompt, $msg))) { Write-Verbose -Message "$functionName`: Stopping runspace pool with the ID: $($RunspacePool.InstanceId)." $RunspacePool.Close() $RunspacePool.Dispose() } } catch { $exception = "$($_.Exception.GetType().FullName)" $msg = "Unhandled error: $_" Write-Warning -Message $exception Write-Warning -Message $msg } } end { Write-Verbose -Message "$functionName`: Entering the end block." } } function New-SynchronizedHashTable { <# .EXTERNALHELP RunspacePoolManager.psm1-Help.xml #> [CmdletBinding(ConfirmImpact = 'Low', SupportsShouldProcess = $false)] [OutputType([System.Collections.Hashtable])] param () begin { $functionName = $($MyInvocation.MyCommand).Name Write-Verbose -Message "$functionName`: Entering the begin block." } process { Write-Verbose -Message "$functionName`: Entering the process block." try { Write-Verbose -Message "$functionName`: Creating synchronized hash table." $return = [hashtable]::Synchronized(@{ }) } catch { $exception = "$($_.Exception.GetType().FullName)" $msg = "Unhandled error: $_" Write-Warning -Message $exception Write-Warning -Message $msg } } end { Write-Verbose -Message "$functionName`: Entering the end block." Write-Output $return } } function New-HashTableKey { <# .EXTERNALHELP RunspacePoolManager.psm1-Help.xml #> [CmdletBinding(ConfirmImpact = 'Low', SupportsShouldProcess = $false)] [alias("Add-HashTableKey")] [alias("New-HTKey")] [alias("Add-HTKey")] param ( [Parameter(Mandatory = $true, Position = 0)] [System.Collections.Hashtable]$HashTable, [Parameter(Mandatory = $true, Position = 1)] [string]$Key, [Parameter(Mandatory = $false, Position = 2)] $Value, [switch]$Force ) begin { $functionName = $($MyInvocation.MyCommand).Name Write-Verbose -Message "$functionName`: Entering the begin block." if ($HashTable.IsReadOnly) { Write-Error -Message "Hash table is read only." break } if (Get-HashTableKey -HashTable $HashTable -Key $Key) { if ($Force) { Set-HashTableKey -HashTable $HashTable -Key $Key -Value $Value break } else { Write-Warning -Message "A key with the name '$Key' already exists in this hash table. Use -Force or Set-HashTableKey." break } } } process { Write-Verbose -Message "$functionName`: Entering the process block." try { Write-Verbose -Message "$functionName`: Adding key '$($Key.tostring())' and value '$($Value.tostring())'." $HashTable.Add($Key, $Value) } catch { $exception = "$($_.Exception.GetType().FullName)" $msg = "Unhandled error: $_" Write-Warning -Message $exception Write-Warning -Message $msg } } end { Write-Verbose -Message "$functionName`: Entering the end block." Write-Output $return } } function Get-HashTableKey { <# .EXTERNALHELP RunspacePoolManager.psm1-Help.xml #> [CmdletBinding(ConfirmImpact = 'Low', SupportsShouldProcess = $false)] [alias("Get-HTKey")] param ( [Parameter(Mandatory = $true, Position = 0)] [System.Collections.Hashtable]$HashTable, [Parameter(Mandatory = $true, Position = 1)] [string]$Key ) begin { $functionName = $($MyInvocation.MyCommand).Name Write-Verbose -Message "$functionName`: Entering the begin block." } process { Write-Verbose -Message "$functionName`: Entering the process block." try { Write-Verbose -Message "$functionName`: Getting key '$Key'." $return = $HashTable["$Key"] } catch { $exception = "$($_.Exception.GetType().FullName)" $msg = "Unhandled error: $_" Write-Warning -Message $exception Write-Warning -Message $msg } } end { Write-Verbose -Message "$functionName`: Entering the end block." Write-Output $return } } function Remove-HashTableKey { <# .EXTERNALHELP RunspacePoolManager.psm1-Help.xml #> [CmdletBinding(ConfirmImpact = 'Low', SupportsShouldProcess = $false)] [alias("Remove-HTKey")] param ( [Parameter(Mandatory = $true, Position = 0)] [System.Collections.Hashtable]$HashTable, [Parameter(Mandatory = $true, Position = 1)] [string]$Key, [switch]$Force ) begin { $functionName = $($MyInvocation.MyCommand).Name Write-Verbose -Message "$functionName`: Entering the begin block." if ((-not (Get-HashTableKey -HashTable $HashTable -Key $Key)) -and (-not ($Force))) { Write-Warning -Message "'$Key' does not exist in the hash table." break } } process { Write-Verbose -Message "$functionName`: Entering the process block." try { Write-Verbose -Message "$functionName`: Removing key '$Key'." $HashTable.Remove($Key) } catch { $exception = "$($_.Exception.GetType().FullName)" $msg = "Unhandled error: $_" Write-Warning -Message $exception Write-Warning -Message $msg } } end { Write-Verbose -Message "$functionName`: Entering the end block." } } function Set-HashTableKey { <# .EXTERNALHELP RunspacePoolManager.psm1-Help.xml #> [CmdletBinding(ConfirmImpact = 'Low', SupportsShouldProcess = $false)] [alias("Set-HTKey")] param ( [Parameter(Mandatory = $true, Position = 0)] [System.Collections.Hashtable]$HashTable, [Parameter(Mandatory = $true, Position = 1)] [string]$Key, [Parameter(Mandatory = $false, Position = 2)] $Value, [switch]$Force ) begin { $functionName = $($MyInvocation.MyCommand).Name Write-Verbose -Message "$functionName`: Entering the begin block." if ($HashTable.IsReadOnly) { Write-Error -Message "Hash table is read only." break } if (-not (Get-HashTableKey -HashTable $HashTable -Key $Key)) { if ($Force) { New-HashTableKey -HashTable $HashTable -Key $Key -Value $Value break } else { Write-Warning -Message "A key with the name '$Key' was not found in this hash table. Use -Force or New-HashTableKey" break } } } process { Write-Verbose -Message "$functionName`: Entering the process block." try { Write-Verbose -Message "$functionName`: Setting key '$($Key.tostring())' too value '$($Value.tostring())'." $HashTable["$Key"] = $Value } catch { $exception = "$($_.Exception.GetType().FullName)" $msg = "Unhandled error: $_" Write-Warning -Message $exception Write-Warning -Message $msg } } end { Write-Verbose -Message "$functionName`: Entering the end block." } } |