Author Posts

June 22, 2016 at 5:47 pm

The code below will demonstrate usage of the Synchronized variable for Runspaces. You can use any ip/hostname for $ComputerName as long it's accessible, Powershell remoting is verified by Enter-PSSession and also you added credential to Windows Credential Manager for $ComputerName as host.

Get-Runspace | ? Id -NE 1 | % { $_.close() ; $_.dispose() }
$Runspace = $powerShell = $connectionInfo = $handle = $hash = $null 
$ComputerName = '192.168.0.3'

$hash = [hashtable]::Synchronized(@{})
$hash.One = 1

Write-host ('Value of $Hash.One before background runspace is {0}' -f $hash.one) -ForegroundColor Green -BackgroundColor Black
$Uri = New-Object System.Uri("http://$($ComputerName):5985/wsman")
$connectionInfo = New-Object System.Management.Automation.Runspaces.WSManConnectionInfo -ArgumentList $Uri
$connectionInfo.AuthenticationMechanism = [System.Management.Automation.Runspaces.AuthenticationMechanism]::Negotiate
$connectionInfo.OpenTimeout = 3000

$Runspace = [runspacefactory]::CreateRunspace($connectionInfo) # don't work
#$Runspace = [runspacefactory]::CreateRunspace() # works

$runspace.Open()
$runspace.SessionStateProxy.SetVariable('Hash',$hash)

$powershell = [powershell]::Create()
$powershell.Runspace = $runspace

$powershell.AddScript({
    $hash.one++
}) | Out-Null #The Out-Null at the end is used to prevent the output of the object that occurs.

$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) -ForegroundColor Green -BackgroundColor Black
As soon as I replace:

$Runspace = [runspacefactory]::CreateRunspace()

with

$Runspace = [runspacefactory]::CreateRunspace($connectionInfo)

(because I want to execute code at the remote computer), the synchronized variable $hash is not updated. Anyone know what I missing? This feature is really important and useful and I need it to make it work for remote runspaces.

  • This topic was modified 2 years, 1 month ago by  AL|EN.

June 22, 2016 at 6:50 pm

As far as I know, you can't do that. Synchronized variables are for sharing the same objects in memory across multiple threads on the same computer. Just because we use runspaces to achieve multithreading in PowerShell locally doesn't mean that you can do all the same tricks with a remote runspace.

June 22, 2016 at 7:36 pm

Hello, Dave. You're looking well today 😉

That's very unfortunately for me. Without it, my script doesn't export logs. Do you know any feature or technique to achieve such synchronization between remote runspaces?

I need a way to:
– from the server A, run several remote runspaces, scriptblock will do some job and the errors will be stored inside [hashtable]$SynchronizedLogs as a computername = errors pairs
– send this data to the server A (for eg to another [Array]$variable), after all runspaces are finished, export it to the file

Any ideas?

June 22, 2016 at 7:47 pm

Personally, I'd just write objects to the output stream.

June 23, 2016 at 8:19 am

Hmmm... I've sleep with this problem and I don't want to sound like I'm not grateful for you feedback but using Write-Output is the last (and ugliest) thing which I could think of. Also it would just put text on the screen without a way to export the data to file. Good thing is that will at least allows me to see errors. I's better than nothing. Thanks anyway.

June 23, 2016 at 11:33 am

I think you misunderstood me. When you write to the output stream, you can assign the results to a variable back in the calling session. It's got nothing to do with showing text on the screen. 🙂

$results = $powershell.EndInvoke($handle)

# Process your results

June 23, 2016 at 1:25 pm

Now it's much more clear. That will do the job 🙂