Synchronized variable don't work for Remote Runspace

Tagged: 

This topic contains 6 replies, has 2 voices, and was last updated by  AL|EN 1 year, 2 months ago.

  • Author
    Posts
  • #44390

    AL|EN
    Participant

    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 1 year, 2 months ago by  AL|EN.
  • #44434

    Dave Wyatt
    Moderator

    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.

  • #44447

    AL|EN
    Participant

    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?

  • #44453

    Dave Wyatt
    Moderator

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

  • #44526

    AL|EN
    Participant

    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.

  • #44530

    Dave Wyatt
    Moderator

    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
    
  • #44540

    AL|EN
    Participant

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

You must be logged in to reply to this topic.