Powershell: foreach-object -parallel working weirdly??

Created on 29 Jan 2020  Â·  3Comments  Â·  Source: PowerShell/PowerShell

Hello all,

Steps:

  1. load var from xml file.
  2. Get all the files on the scripts directory and start a job foreach file.

so whats wrong?. If I use -parallel the value $SettingsXML.settings.ScriptsPath is gone while if I use -process this will work correctly, the jobs will start and finish without any problem

Example value:
$SettingsXML.settings.ScriptsPath = C:\Users\WhateverUser\Desktop\Powershell\Scripts

not quite sure if i am miss using the -pararllel, if that is the case then just ignore this and close it
I feel like -parallel can only accede to $_. which i do not know if this is the expected behavior.

Steps to reproduce

#load settings.xml
$path = $PSScriptRoot+"\settings.xml"
[xml]$SettingsXML = Get-Content -Path $path

Get-ChildItem -Path $SettingsXML.settings.ScriptsPath | ForEach-Object -parallel  `
{
    #test var
    $SettingsXML.Settings.ScriptsPath
    $_.Name
    #job command
    Start-ThreadJob -Name ($_.Name.Replace(".ps1","")) -FilePath "$($SettingsXML.Settings.ScriptsPath)\$($_.Name)" -ArgumentList (,$ServerName)
}

Expected behavior

  The jobs are created and executed.

Actual behavior

   as the $SettingsXML.settings.ScriptsPath is gone inside -parallel the job won't start because the path to the others scripts will be wrong

Start-ThreadJob: 
Line |
   4 |      Start-ThreadJob -Name ($_.Name.Replace(".ps1","")) -FilePath "$($ …

     |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot find path 'C:\whatEverScript.ps1(the script name is correct so $_.name is working)' because it does not exist.

Environment data

Name                           Value
----                           -----
PSVersion                      7.0.0-rc.2
PSEdition                      Core
GitCommitId                    7.0.0-rc.2
OS                             Microsoft Windows 10.0.18363
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Issue-Question Resolution-Answered

Most helpful comment

Because ForEach-Object -Parallel executes in different runspaces, variables will typically not be directly available. I believe you can use $using:varname to access variables from the wider script.

Word of warning: I don't know how threadsafe XmlDocument is. Most things work OK if you're just reading from them, but if you run into issues I'd pull the value you're using out into it's own variable rather than having it accessed through the XmlDocument every time. :slightly_smiling_face:

All 3 comments

Because ForEach-Object -Parallel executes in different runspaces, variables will typically not be directly available. I believe you can use $using:varname to access variables from the wider script.

Word of warning: I don't know how threadsafe XmlDocument is. Most things work OK if you're just reading from them, but if you run into issues I'd pull the value you're using out into it's own variable rather than having it accessed through the XmlDocument every time. :slightly_smiling_face:

Also, note that each execution of a script-block used with ForEach-Object -Parallel already _is_ a thread job of sorts, so there's probably no reason to call Start-ThreadJob from within it.

Please consider closing your question, @JrrRomeroJose; either way, for discoverability, please correct the typo in the title: where-object -> foreach-object

@mklement0 100% right.

Was this page helpful?
0 / 5 - 0 ratings