diff --git a/README.md b/README.md index c951148..8fa9d92 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,246 @@ # Invoke-PSThread -Enables the ability to leverage multithreading within powershell whilst reducing the complexity to get started. + .SYNOPSIS + Enables the ability to leverage multithreading within powershell whilst reducing the complexity to get started. + + .DESCRIPTION + This function aims to remove the enormous complexity out of multithreading within powershell. See the fully working examples below. + + .PARAMETER Runspace + Your parameter description + + .PARAMETER RunspacePool + Your parameter description + + .PARAMETER Await + Your parameter description + + .PARAMETER RunspaceDefinition + Your parameter description + + .PARAMETER RunspaceParameters + Your parameter description + + .PARAMETER InputObjectList + Your parameter description + + .PARAMETER SynchronizedHashtable + Your parameter description + + .PARAMETER AssemblyList + Your parameter description + + .PARAMETER FunctionList + Your parameter description + + .PARAMETER ModuleList + Your parameter description + + .PARAMETER VariableList + Your parameter description + + .PARAMETER ThreadList + Your parameter description + + .PARAMETER LoopTimeout + Your parameter description + + .PARAMETER LoopDuration + Your parameter description + + .PARAMETER WaitForAvailableRunspace + Your parameter description + + .PARAMETER ContinueOnError + Your parameter description + + .EXAMPLE + Create a runspace + + [ScriptBlock]$RunspaceDefinition = { + Param + ( + $SynchronizedHashtable, + $Title, + $Message + ) + + $Null = Add-Type -AssemblyName 'System.Windows.Forms' + $Null = Add-Type -AssemblyName 'System.Drawing' + + $Form = New-Object -TypeName 'System.Windows.Forms.Form' + $Form.Size = New-Object -TypeName 'System.Drawing.Size' -ArgumentList @(300,150) + + $TextBox = New-Object -TypeName 'System.Windows.Forms.RichTextBox' + $TextBox.Location = New-Object -TypeName 'System.Drawing.Point' -ArgumentList @(110,50) + $TextBox.BorderStyle = 0 + $TextBox.BackColor = $Form.BackColor + + $TextBox.Text = $Message + + $Null = $Form.Controls.Add($TextBox) + + $Null = $Form.ShowDialog() + } + + $SynchronizedHashtable = [System.Collections.Hashtable]::Synchronized(@{}) + $SynchronizedHashtable.ThreadIDList = New-Object -TypeName 'System.Collections.Generic.List[System.String]' + + $InvokePSThreadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokePSThreadParameters.Runspace = $True + $InvokePSThreadParameters.RunspaceDefinition = $RunspaceDefinition + $InvokePSThreadParameters.RunspaceParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokePSThreadParameters.RunspaceParameters.Title = "This is my UI title" + $InvokePSThreadParameters.RunspaceParameters.Message = "This is my UI message.`r`nThis is the second line of my UI message.`r`nThis is the third line of my UI message." + $InvokePSThreadParameters.SynchronizedHashtable = Get-Variable -Name 'SynchronizedHashtable' -ErrorAction SilentlyContinue + $InvokePSThreadParameters.FunctionList = Get-ChildItem -Path 'Function:' | Where-Object {($_.Name -iin @('Test'))} + $InvokePSThreadParameters.ModuleList = Get-Module | Where-Object {($_.Name -iin @('Test'))} + $InvokePSThreadParameters.VariableList = Get-Variable | Where-Object {($_.Name -iin @('Test'))} + $InvokePSThreadParameters.ContinueOnError = $False + $InvokePSThreadParameters.Verbose = $True + + $InvokePSThreadResult = Invoke-PSThread @InvokePSThreadParameters + + Write-Output -InputObject ($InvokePSThreadResult) + + .EXAMPLE + Create a runspace pool, submit all jobs to the pool, and the pool will manage their execution. + + [ScriptBlock]$RunspaceDefinition = { + Param + ( + $InputObjectListItem, + $SynchronizedHashtable, + $AdditionalParameter1, + $AdditionalParameter2 + ) + + #Set thread priority + [System.Threading.Thread]::CurrentThread.Priority = [System.Threading.ThreadPriority]::Lowest + + $ThreadInfo = [System.Threading.Thread]::CurrentThread + + $ThreadID = [System.AppDomain]::GetCurrentThreadId() + + $SynchronizedHashtable.ThreadIDList.Add($ThreadID) + + Write-Verbose -Message "Attempting to begin thread ID `"$($ThreadID)`". Please Wait..." -Verbose + + $SynchronizedHashtable.Add("Thread$($ThreadID)", (Get-Date)) + + Write-Output -InputObject ($InputObjectListItem) + + Write-Output -InputObject ($AdditionalParameter1) + + Write-Output -InputObject ($AdditionalParameter2) + + $Null = Start-Sleep -Seconds (Get-Random -Minimum 10 -Maximum 25) + } + + $SynchronizedHashtable = [System.Collections.Hashtable]::Synchronized(@{}) + $SynchronizedHashtable.ThreadIDList = New-Object -TypeName 'System.Collections.Generic.List[System.String]' + + $InvokePSThreadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokePSThreadParameters.RunspacePool = $True + $InvokePSThreadParameters.InputObjectList = 1..15 + $InvokePSThreadParameters.RunspaceDefinition = $RunspaceDefinition + $InvokePSThreadParameters.RunspaceParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokePSThreadParameters.RunspaceParameters.AdditionalParameter1 = Get-Random -Minimum 0 -Maximum 10000 + $InvokePSThreadParameters.RunspaceParameters.AdditionalParameter2 = Get-Random -Minimum 0 -Maximum 10000 + $InvokePSThreadParameters.SynchronizedHashtable = Get-Variable -Name 'SynchronizedHashtable' -ErrorAction SilentlyContinue + $InvokePSThreadParameters.FunctionList = Get-ChildItem -Path 'Function:' | Where-Object {($_.Name -iin @('Test'))} + $InvokePSThreadParameters.ModuleList = Get-Module | Where-Object {($_.Name -iin @('Test'))} + $InvokePSThreadParameters.VariableList = Get-Variable | Where-Object {($_.Name -iin @('Test'))} + $InvokePSThreadParameters.ContinueOnError = $False + $InvokePSThreadParameters.Verbose = $True + + $InvokePSThreadResult = Invoke-PSThread @InvokePSThreadParameters + + Write-Output -InputObject ($InvokePSThreadResult) + + .EXAMPLE + Create a runspace pool, submit all jobs to the pool, and the pool will manage their execution. The function will be executed a second time to wait until all jobs have been completed, return their output, and cleanup. + + [ScriptBlock]$RunspaceDefinition = { + Param + ( + $InputObjectListItem, + $SynchronizedHashtable, + $AdditionalParameter1, + $AdditionalParameter2 + ) + + #Set thread priority + [System.Threading.Thread]::CurrentThread.Priority = [System.Threading.ThreadPriority]::Lowest + + $ThreadInfo = [System.Threading.Thread]::CurrentThread + + $ThreadID = [System.AppDomain]::GetCurrentThreadId() + + $SynchronizedHashtable.ThreadIDList.Add($ThreadID) + + Write-Verbose -Message "Attempting to begin thread ID `"$($ThreadID)`". Please Wait..." -Verbose + + $SynchronizedHashtable.Add("Thread$($ThreadID)", (Get-Date)) + + Write-Output -InputObject ($InputObjectListItem) + + Write-Output -InputObject ($AdditionalParameter1) + + Write-Output -InputObject ($AdditionalParameter2) + + $Null = Start-Sleep -Seconds (Get-Random -Minimum 10 -Maximum 25) + } + + $SynchronizedHashtable = [System.Collections.Hashtable]::Synchronized(@{}) + $SynchronizedHashtable.ThreadIDList = New-Object -TypeName 'System.Collections.Generic.List[System.String]' + + $InvokePSThreadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokePSThreadParameters.RunspacePool = $True + $InvokePSThreadParameters.InputObjectList = Get-Process | Get-Random -Count 15 + $InvokePSThreadParameters.RunspaceDefinition = $RunspaceDefinition + $InvokePSThreadParameters.RunspaceParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokePSThreadParameters.RunspaceParameters.AdditionalParameter1 = Get-Random -Minimum 0 -Maximum 10000 + $InvokePSThreadParameters.RunspaceParameters.AdditionalParameter2 = Get-Random -Minimum 0 -Maximum 10000 + $InvokePSThreadParameters.SynchronizedHashtable = Get-Variable -Name 'SynchronizedHashtable' -ErrorAction SilentlyContinue + $InvokePSThreadParameters.FunctionList = Get-ChildItem -Path 'Function:' | Where-Object {($_.Name -iin @('Test'))} + $InvokePSThreadParameters.ModuleList = Get-Module | Where-Object {($_.Name -iin @('Test'))} + $InvokePSThreadParameters.VariableList = Get-Variable | Where-Object {($_.Name -iin @('Test'))} + $InvokePSThreadParameters.ContinueOnError = $False + $InvokePSThreadParameters.Verbose = $True + + $InvokePSThreadResult = Invoke-PSThread @InvokePSThreadParameters + + #Do some additional code here + + $InvokePSThreadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokePSThreadParameters.Await = $True + $InvokePSThreadParameters.ThreadList = $InvokePSThreadResult + $InvokePSThreadParameters.LoopTimeout = [System.TimeSpan]::FromHours(1) + $InvokePSThreadParameters.LoopDuration = [System.TimeSpan]::FromMilliseconds(15000) + $InvokePSThreadParameters.ContinueOnError = $False + $InvokePSThreadParameters.Verbose = $True + + $ThreadAwaitResult = Invoke-PSThread @InvokePSThreadParameters + + Write-Output -InputObject ($ThreadAwaitResult) + + .NOTES + Any useful tidbits + + .LINK + https://davewyatt.wordpress.com/2014/04/29/more-potential-use-cases-for-thread-safe-variable-access-in-powershell-events/ + + .LINK + https://davewyatt.wordpress.com/2014/04/29/more-potential-use-cases-for-thread-safe-variable-access-in-powershell-events/ + + .LINK + https://www.codeproject.com/Tips/895840/Multi-Threaded-PowerShell-Cookbook + + .LINK + https://www.linkedin.com/pulse/multithreading-powershell-scripts-alexey/ + + .LINK + https://xkln.net/blog/multithreading-in-powershell--running-a-specific-number-of-threads/ + + .LINK + https://markw.dev/#:~:text=There%20are%20two%20ways%20we,other%20is%20by%20using%20splatting.&text=The%20important%20part%20here%20is,plural)%20instead%20of%20AddParameter()%20.