GuidoT
GuidoT

Reputation: 322

New-PSSession freezes script

I would like to create multiple Powershell sessions to my local machine to perform some operations on many files / folders at once, without slowing down my actual Powershell script. Therefore I was looking for possibilities to do multi-threading in Powershell.

The easiest approach appears to be the New-PSSession cmdlet. I created a test script to play around with it.

Write-Host "Creating session"
$NewSession = New-PSSession
Write-Host "Session created" #This line will not show up anymore...
Invoke-Command -Session $NewSession -ScriptBlock {$WSH = Create-Object -comObject WScript.Shell; $WSH.Popup("Some popup", 1) } -AsJob

Whenever I run it, it simply freezes when calling New-PSSession

What am I doing wrong?

Upvotes: 2

Views: 2119

Answers (2)

codewario
codewario

Reputation: 21518

Seems New-PSSession hangs when not providing arguments. This is not really what New-PSSession is meant for anyways, you should prefer the Start-Job cmdlets (or you could use Start-ThreadJob if available to you). An example:

$myFirstName = "Bender"
$myLastName = "the Greatest"

$jobWithArgs = Start-Job -ArgumentList $myFirstName, $myLastName -ScriptBlock {
  Write-Output "My name is $($args[0]) $($args[1])"
}

# Do Local Script Stuff

$jobResult = Receive-Job $job -Wait

# Process the job result

Receive-Job -Wait will block until all job results have been received. Basically it'll wait for the job to finish so you don't have to write any boilerplate around that. -ArgumentList is optional and is used to pass in an array of arguments that can be processed within the job.

Here are additional Microsoft resources for Start-Job and Receive-Job:

Upvotes: 2

Alexander Martin
Alexander Martin

Reputation: 483

It is not necessary to create sessions to run commands in the background; just use the -AsJob switch to Invoke-Command and collect the resulting job objects. When you want the results, pass them to Receive-Job.

# Not optimal for a few reasons; this is just example code.

$jobs = @()
foreach ($block in $scriptBlocksToRun) {
  $jobs += (Invoke-Command -ScriptBlock $block -AsJob)
}

# Do things that don't depend on job results here...

foreach ($job in $jobs) {
  $output = $job | Receive-Job
  # Do something with output here...
}

Obviously, you should consult the documentation for Invoke-Command and Receive-Job for more details.

Upvotes: 0

Related Questions