Q:

When using Powershell Jobs, Runspaces, or Workflows, are the threads being executed on separate cores?

When using Powershell Jobs, Runspaces, or Workflows, are the threads being executed on separate cores? (and if so, how do we tell powershell how many cores to use? -- sorry that's 2 questions.)
.Net has the Task Parallel Library, which allows a 'for loop' to run in parallel, using all available cores (here is one example).  Does Powershell Jobs, Runspaces, or Workflows do something similar?  And by similar, I mean are the threads actually running on separate cores, in parallel?
I found a similar question here, but it seems unclear (to me anyway) if the threads are executed on separate cores.  It seems that sometimes multi-threads are mistaken for parallel, as mentioned here.
If using multiple cores with Powershell is not possible, I will use C# or perhaps Python, but my first choice is to use Powershell because (insert long list of reasons).
If it's relevant, I'm trying to do all this to help a co-worker who does server admin type stuff.  Currently, his powershell script loops through a list of servers, and foreach server, does stuff.  Currently the script runs on an 8 core machine, but is only using one core. I'm sure there are other ways to boost performance, but doing it in parallel is my current goal.

A:

I would say yes if by separate cores, you mean logical cores (not physical cores). Run something like this and notice the output from “$num”.  $num represents the current logical (not physical) core on which a thread is running.  If this script runs on a dual core machine (with 4 logical cores), the output of $num is a 0, 1, 2, or 3.  See here for a better explanation on Logical vs Physical CPU.
$sb = {
    param($sbarg)
$MethodDefinition = @'
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern int GetCurrentProcessorNumber();
'@

    $Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name 'Kernel32' -Namespace 'Win32' -PassThru

    0..10 | % {
    $num = $Kernel32::GetCurrentProcessorNumber() 
    Write-Output "[$sbarg]:[$_] on '$num'"

    # simulate some work that may make the cpu busy
    # perhaps watch in task manager as well to see load
    $result = 1; foreach ($number in 1..1000000) {$result = $result * $number};

    Start-Sleep -Milliseconds 500
    }
}

0..10 | % {
    Start-Job -ScriptBlock $sb -ArgumentList $_
}

Get-Job

# Wait for it all to complete
While (Get-Job -State "Running")
{
    Write-Output "waiting..."
    Start-Sleep 2
}

# Getting the information back from the jobs
Get-Job | Receive-Job

# Clean Up
Get-Job | Remove-Job

