Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/System.Management.Automation/engine/InternalCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ public void Dispose()
private PSTaskJob _taskJob;
private PSDataCollection<System.Management.Automation.PSTasks.PSTask> _taskCollection;
private Exception _taskCollectionException;
private string _currentLocationPath;

private void InitParallelParameterSet()
{
Expand All @@ -393,6 +394,15 @@ private void InitParallelParameterSet()
this));
}

// Get the current working directory location, if available.
try
{
_currentLocationPath = SessionState.Internal.CurrentLocation.Path;
}
catch (PSInvalidOperationException)
{
}

bool allowUsingExpression = this.Context.SessionState.LanguageMode != PSLanguageMode.NoLanguage;
_usingValuesMap = ScriptBlockToPowerShellConverter.GetUsingValuesAsDictionary(
Parallel,
Expand Down Expand Up @@ -486,10 +496,10 @@ private void InitParallelParameterSet()
}
catch (Exception ex)
{
// Close the _taskCollection on an unexpected exception so the pool closes and
// lets any running tasks complete.
_taskCollection.Complete();
_taskCollectionException = ex;
_taskDataStreamWriter.Close();

break;
}

Expand Down Expand Up @@ -528,7 +538,8 @@ private void ProcessParallelParameterSet()
var taskChildJob = new PSTaskChildJob(
Parallel,
_usingValuesMap,
InputObject);
InputObject,
_currentLocationPath);

_taskJob.AddJob(taskChildJob);

Expand All @@ -550,6 +561,7 @@ private void ProcessParallelParameterSet()
Parallel,
_usingValuesMap,
InputObject,
_currentLocationPath,
_taskDataStreamWriter));
}
catch (InvalidOperationException)
Expand Down
38 changes: 33 additions & 5 deletions src/System.Management.Automation/engine/hostifaces/PSTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,19 @@ internal sealed class PSTask : PSTaskBase
/// <param name="scriptBlock">Script block to run in task.</param>
/// <param name="usingValuesMap">Using values passed into script block.</param>
/// <param name="dollarUnderbar">Dollar underbar variable value.</param>
/// <param name="currentLocationPath">Current working directory.</param>
/// <param name="dataStreamWriter">Cmdlet data stream writer.</param>
public PSTask(
ScriptBlock scriptBlock,
Dictionary<string, object> usingValuesMap,
object dollarUnderbar,
string currentLocationPath,
PSTaskDataStreamWriter dataStreamWriter)
: base(
scriptBlock,
usingValuesMap,
dollarUnderbar)
dollarUnderbar,
currentLocationPath)
{
_dataStreamWriter = dataStreamWriter;
}
Expand Down Expand Up @@ -176,15 +179,18 @@ internal sealed class PSJobTask : PSTaskBase
/// <param name="scriptBlock">Script block to run.</param>
/// <param name="usingValuesMap">Using variable values passed to script block.</param>
/// <param name="dollarUnderbar">Dollar underbar variable value for script block.</param>
/// <param name="currentLocationPath">Current working directory.</param>
/// <param name="job">Job object associated with task.</param>
public PSJobTask(
ScriptBlock scriptBlock,
Dictionary<string, object> usingValuesMap,
object dollarUnderbar,
string currentLocationPath,
Job job) : base(
scriptBlock,
usingValuesMap,
dollarUnderbar)
dollarUnderbar,
currentLocationPath)
{
_job = job;
}
Expand Down Expand Up @@ -309,6 +315,7 @@ internal abstract class PSTaskBase : IDisposable
private readonly Dictionary<string, object> _usingValuesMap;
private readonly object _dollarUnderbar;
private readonly int _id;
private readonly string _currentLocationPath;
private Runspace _runspace;
protected PowerShell _powershell;
protected PSDataCollection<PSObject> _output;
Expand Down Expand Up @@ -372,14 +379,17 @@ private PSTaskBase()
/// <param name="scriptBlock">Script block to run.</param>
/// <param name="usingValuesMap">Using variable values passed to script block.</param>
/// <param name="dollarUnderbar">Dollar underbar variable value.</param>
/// <param name="currentLocationPath">Current working directory.</param>
protected PSTaskBase(
ScriptBlock scriptBlock,
Dictionary<string, object> usingValuesMap,
object dollarUnderbar) : this()
object dollarUnderbar,
string currentLocationPath) : this()
{
_scriptBlockToRun = scriptBlock;
_usingValuesMap = usingValuesMap;
_dollarUnderbar = dollarUnderbar;
_currentLocationPath = currentLocationPath;
}

#endregion
Expand Down Expand Up @@ -428,6 +438,22 @@ public void Start()
_runspace.Name = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", RunspaceName, s_taskId);
_runspace.Open();

// If available, set current working directory on the runspace.
// Temporarily set the newly created runspace as the thread default runspace for any needed module loading.
if (_currentLocationPath != null)
{
var oldDefaultRunspace = Runspace.DefaultRunspace;
try
{
Runspace.DefaultRunspace = _runspace;
_runspace.ExecutionContext.SessionState.Internal.SetLocation(_currentLocationPath);
}
finally
{
Runspace.DefaultRunspace = oldDefaultRunspace;
}
}

// Create the PowerShell command pipeline for the provided script block
// The script will run on the provided Runspace in a new thread by default
_powershell = PowerShell.Create(_runspace);
Expand Down Expand Up @@ -1216,15 +1242,17 @@ private PSTaskChildJob() { }
/// <param name="scriptBlock">Script block to run.</param>
/// <param name="usingValuesMap">Using variable values passed to script block.</param>
/// <param name="dollarUnderbar">Dollar underbar variable value.</param>
/// <param name="currentLocationPath">Current working directory.</param>
public PSTaskChildJob(
ScriptBlock scriptBlock,
Dictionary<string, object> usingValuesMap,
object dollarUnderbar)
object dollarUnderbar,
string currentLocationPath)
: base(scriptBlock.ToString(), string.Empty)

{
PSJobTypeName = nameof(PSTaskChildJob);
_task = new PSJobTask(scriptBlock, usingValuesMap, dollarUnderbar, this);
_task = new PSJobTask(scriptBlock, usingValuesMap, dollarUnderbar, currentLocationPath, this);
_task.StateChanged += (sender, args) => HandleTaskStateChange(sender, args);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ Describe 'ForEach-Object -Parallel Basic Tests' -Tags 'CI' {
$results = 1..1 | ForEach-Object -Parallel { $ExecutionContext.SessionState.LanguageMode }
$results | Should -BeExactly 'FullLanguage'
}

It 'Verifies that the current working directory is preserved' {
$parallelScriptLocation = 1..1 | ForEach-Object -Parallel { $pwd }
$parallelScriptLocation.Path | Should -BeExactly $pwd.Path
}
}

Describe 'ForEach-Object -Parallel common parameters' -Tags 'CI' {
Expand Down Expand Up @@ -344,6 +349,13 @@ Describe 'ForEach-Object -Parallel -AsJob Basic Tests' -Tags 'CI' {
$job.ChildJobs[0].Command | Should -BeExactly '"Hello"'
$job | Wait-Job | Remove-Job
}

It 'Verifies that the current working directory is preserved' {
$job = 1..1 | ForEach-Object -AsJob -Parallel { $pwd }
$parallelScriptLocation = $job | Wait-Job | Receive-Job
$job | Remove-Job
$parallelScriptLocation.Path | Should -BeExactly $pwd.Path
}
}

Describe 'ForEach-Object -Parallel Functional Tests' -Tags 'Feature' {
Expand Down