Synchronized Collections
As an example I’m passing a synchronized hash table into a powershell job.
> Write-Host "PSJobs with a synchronized collection"
> $hash = [hashtable]::Synchronized(@{})
> $hash.One = 1
> Write-host ('Value of $Hash.One before PSjob is {0}' -f $hash.one)
Value of $Hash.One before PSjob is 1
> Start-Job -Name TestSync -ScriptBlock {
Param ($hash)
$hash.One++
} -ArgumentList $hash | Out-Null
> Get-Job -Name TestSync | Wait-Job | Out-Null
> Write-host ('Value of $Hash.One after PSjob is {0}' -f $hash.one)
Value of $Hash.One after PSjob is 1
Get-Job | Remove-Job
As expected the original hash tables stays unmodified.
This is because ‘Start-Job’ spawns a new powershell.
Synchronized hash table with a single runspace
We will now create a runspace add our hash table to it, add a script block.
After that we add our runspace to a newly created Powershell instance and run it.
Waiting for the script to finish before cleaning up and writing our values to the console.
$hash = [hashtable]::Synchronized(@{})
$hash.One = 1
Write-host ('Value of $Hash.One before background runspace is {0}' -f $hash.one)
$runspace = [runspacefactory]::CreateRunspace()
$runspace.Open()
$runspace.SessionStateProxy.SetVariable('Hash',$hash)
$powershell = [powershell]::Create()
$powershell.Runspace = $runspace
$powershell.AddScript({
$hash.one++
}) | Out-Null
$handle = $powershell.BeginInvoke()
While (-Not $handle.IsCompleted) {
Start-Sleep -Milliseconds 100
}
$powershell.EndInvoke($handle)
$runspace.Close()
$powershell.Dispose()
Write-host ('Value of $Hash.One after background runspace is {0}' -f $hash.one)
Output
Value of $Hash.One before background runspace is 1
Value of $Hash.One after background runspace is 2
Example
Let’s add some more values that might be useful.
Look at the ‘Host’ value where the host runspace is passed to created runspace.
Also, take note of the 10 seconds ‘Start-Sleep’ which gives me the time to manipulate values from the parent session
$hash = [hashtable]::Synchronized(@{})
$hash.value = 1
$hash.Flag = $True
$hash.Host = $host
Write-host ('Value of $Hash.value before background runspace is {0}' -f $hash.value)
$runspace = [runspacefactory]::CreateRunspace()
$runspace.Open()
$runspace.SessionStateProxy.SetVariable('Hash',$hash)
$powershell = [powershell]::Create()
$powershell.Runspace = $runspace
$powershell.AddScript({
While ($hash.Flag) {
$hash.value++
$hash.Services = Get-Service
$hash.host.ui.WriteVerboseLine($hash.value)
Start-Sleep -Seconds 10
}
}) | Out-Null
$handle = $powershell.BeginInvoke()
Output parent session
VERBOSE 2
VERBOSE 3
...
Manipulate values from parent session during runtime
VERBOSE 7
> $hash.value = -10
VERBOSE -9
VERBOSE -8
VERBOSE -7
...
> $hash.Flag = $false
Setting $hash.Flag = $false will break the loop.
Source
This has been stolen here: https://learn-powershell.net/2013/04/19/sharing-variables-and-live-objects-between-powershell-runspaces/