How can I print to the console inside a PowerShell parallel loop

2.8k views Asked by At

I have a simple workflow for running some commands within a parallel foreach loop, but cannot figure out how to print to the console from within the loop.

$names = @('foo', 'bar', 'bat')
Workflow Test-Print
{
    foreach -Parallel ($name in $names)
    {
        # execute some commands on #name

        (InlineScript {Write-Host "Hello $name";}) # doesn't print
        Write-Output "Hello $name" # doesn't print
        Write-Host "Hello $name" # error
        Write-Information "Hello $name" # doesn't print
        Write-Verbose "Hello $name" # doesn't print, even with -Verbose flag
    }
}

Test-Print -Verbose
1

There are 1 answers

0
postanote On

This works as designed. Note just the minor change I made.

workflow ForEachParaTest {

   param([string[]]$computers)

   'OS & PowerShell Version'
   (Get-CimInstance -ClassName Win32_OperatingSystem).Caption
   $PSVersionTable

   foreach –parallel ($computer in $computers)
   {

    # Write current target to screen
    "Processing $computer"

   }

}
ForEachParaTest -Computers 'server01', 'server02', 'server03' 

<#
# Results

OS & PowerShell Version
Microsoft Windows 10 Pro

Name                           Value
----                           -----
PSRemotingProtocolVersion      2.3
BuildVersion                   10.0.18362.752
PSVersion                      5.1.18362.752
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0, 5.0, 5.1.18362.752}
PSEdition                      Desktop
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
SerializationVersion           1.1.0.1

Processing server03
Processing server02
Processing server01
#>

If I add back in all you had. You can see that of the 6 options, only 4 will be successful.

workflow ForEachParaTest {

   param([string[]]$computers)

   'OS & PowerShell Version'
   (Get-CimInstance -ClassName Win32_OperatingSystem).Caption
   $PSVersionTable

   foreach –parallel ($computer in $computers)
   {

    # Write current target to screen
    # Using PS Default
    "`nProcessing $computer using PowerShell default output`n"

    (InlineScript {Write-Host "`nProcessing $computer using Write-Host via inline script for output`n"}) 

    Write-Output "`nProcessing localhost using Write-Output for output`n"

    Write-Host "`nProcessing $computer using Write-Host for output`n" 

    Write-Information "`nProcessing $computer using Write-Information for output`n"

    Write-Verbose "`nProcessing $computer using Write-Verbose for output`n"

   }

}
ForEachParaTest -Computers 'server01', 'server02', 'server03'

<#
# Results

At line:20 char:5
+     Write-Host "`nProcessing $computer using Write-Host for output`n"
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Cannot call the 'Write-Host' command. Other commands from this module... 
command requires an interactive Windows PowerShell session, or has be...
Write-Host }) where it will be invoked in isolation.
    + CategoryInfo          : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : CommandActivityExcluded

OS & PowerShell Version
Microsoft Windows 10 Pro

Name                           Value                                                                                                                                                       
----                           -----                                                                                                                                                       
PSRemotingProtocolVersion      2.3                                                                                                                                                         
BuildVersion                   10.0.18362.752                                                                                                                                              
PSVersion                      5.1.18362.752                                                                                                                                               
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0, 5.0, 5.1.18362.752}                                                                                                                    
PSEdition                      Desktop                                                                                                                                                     
CLRVersion                     4.0.30319.42000                                                                                                                                             
WSManStackVersion              3.0                                                                                                                                                         
SerializationVersion           1.1.0.1  

Processing server03
Processing server02
Processing server01

server01
server02
server03

server01
server02
server03

server01
server02
server03
#>

In general practice, Write-Host should just be avoided, except when absolutely needed. Think color, other formatting particulars that won't work without it. Also, as you'll note, if you run this, the "`n" are also not being processed in the WorkFlow, wherein normal cases, it would be.

Now, this way, we get a bit better rendering and commenting out the problem children.

workflow ForEachParaTest {

   param([string[]]$computers)

   'OS & PowerShell Version'
   (Get-CimInstance -ClassName Win32_OperatingSystem).Caption
   "`n"
   $PSVersionTable
   "`n"

   foreach –parallel ($computer in $computers)
   {

    "Processing $computer"

    # (InlineScript {Write-Host "`nProcessing $computer using Write-Host via inline script for output`n"}) 

    Write-Output "`nProcessing $computer using Write-Output for output`n"

    # Write-Host "`nProcessing $computer using Write-Host for output`n"

    Write-Information "`nProcessing $computer using Write-Information for output`n"

    Write-Verbose "`nProcessing $computer using Write-Verbose for output`n"

   }

}
ForEachParaTest -Computers 'server01', 'server02', 'server03' 

<#
# Results

OS & PowerShell Version
Microsoft Windows 10 Pro                      
BuildVersion                   10.0.18362.752
PSVersion                      5.1.18362.752
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0, 5.0, 5.1.18362.752}
PSEdition                      Desktop
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
SerializationVersion           1.1.0.1


Processing server03
Processing server02
Processing server01

Processing server03 using Write-Output for output


Processing server02 using Write-Output for output


Processing server01 using Write-Output for output
#>

Now, back to your original post and this small change:

$names = @('foo', 'bar', 'bat')
Workflow Test-Print
{
    param([string[]]$names)
    foreach -Parallel ($name in $names)
    {
        # execute some commands on #name

        # (InlineScript {Write-Host "Hello $name";}) # doesn't print
        Write-Output "Hello $name" # doesn't print
        # Write-Host "Hello $name" # error
        Write-Information "Hello $name" # doesn't print
        Write-Verbose "Hello $name" # doesn't print, even with -Verbose flag
    }
}


Test-Print $names 

<#
# Results

Hello bat
Hello bar
Hello foo
#>

Test-Print $names -Verbose
<#
# Results

Hello bat
Hello bar
Hello foo
VERBOSE: [localhost]:Hello bat
VERBOSE: [localhost]:Hello bar
VERBOSE: [localhost]:Hello foo
#>