Skip to content

Commit 9213b77

Browse files
authored
Allow commands to still be executed even if the current working directory no longer exists (PowerShell#17579)
1 parent 2051c5f commit 9213b77

File tree

4 files changed

+71
-4
lines changed

4 files changed

+71
-4
lines changed

src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,8 +1908,12 @@ protected override void BeginProcessing()
19081908
}
19091909
else
19101910
{
1911-
// Working Directory not specified -> Assign Current Path.
1912-
startInfo.WorkingDirectory = PathUtils.ResolveFilePath(this.SessionState.Path.CurrentFileSystemLocation.Path, this, isLiteralPath: true);
1911+
// Working Directory not specified -> Assign Current Path, but only if it still exists
1912+
var currentDirectory = PathUtils.ResolveFilePath(this.SessionState.Path.CurrentFileSystemLocation.Path, this, isLiteralPath: true);
1913+
if (Directory.Exists(currentDirectory))
1914+
{
1915+
startInfo.WorkingDirectory = currentDirectory;
1916+
}
19131917
}
19141918

19151919
if (this.ParameterSetName.Equals("Default"))

src/System.Management.Automation/engine/CommandPathSearch.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,17 @@ private void ResolveCurrentDirectoryInLookupPaths()
110110
sessionState.CurrentDrive.Provider.NameEquals(fileSystemProviderName) &&
111111
sessionState.IsProviderLoaded(fileSystemProviderName);
112112

113-
string environmentCurrentDirectory = Directory.GetCurrentDirectory();
113+
string? environmentCurrentDirectory = null;
114+
115+
try
116+
{
117+
environmentCurrentDirectory = Directory.GetCurrentDirectory();
118+
}
119+
catch (FileNotFoundException)
120+
{
121+
// This can happen if the current working directory is deleted by another process on non-Windows
122+
// In this case, we'll just ignore it and continue on with the current directory as null
123+
}
114124

115125
LocationGlobber pathResolver = _context.LocationGlobber;
116126

src/System.Management.Automation/engine/NativeCommandProcessor.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1378,7 +1378,12 @@ private ProcessStartInfo GetProcessStartInfo(
13781378
string rawPath =
13791379
context.EngineSessionState.GetNamespaceCurrentLocation(
13801380
context.ProviderNames.FileSystem).ProviderPath;
1381-
startInfo.WorkingDirectory = WildcardPattern.Unescape(rawPath);
1381+
1382+
// Only set this if the PowerShell's current working directory still exists.
1383+
if (Directory.Exists(rawPath))
1384+
{
1385+
startInfo.WorkingDirectory = WildcardPattern.Unescape(rawPath);
1386+
}
13821387

13831388
return startInfo;
13841389
}

test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,54 @@ Describe 'native commands with pipeline' -tags 'Feature' {
5151
Start-Sleep -Milliseconds 500
5252
(Get-Process 'yes' -ErrorAction Ignore).Count | Should -Be $yes
5353
}
54+
55+
It 'native command should still execute if the current working directory no longer exists with command: <command>' -Skip:($IsWindows) -TestCases @(
56+
@{ command = 'ps' }
57+
@{ command = 'start-process ps -nonewwindow'}
58+
){
59+
param($command)
60+
61+
$wd = New-Item testdrive:/tmp -ItemType directory
62+
$lock = New-Item testdrive:/lock -ItemType file
63+
$script = @"
64+
while (`$null -ne (Get-Item "$lock" -ErrorAction Ignore)) {
65+
Start-Sleep -Seconds 1
66+
}
67+
68+
try {
69+
`$out = $command
70+
}
71+
catch {
72+
`$null = Set-Content -Path "$testdrive/error" -Value (`$_ | Out-String)
73+
}
74+
75+
`$null = Set-Content -Path "$testdrive/out" -Value `$out
76+
"@
77+
78+
$pwsh = Start-Process -FilePath "${PSHOME}/pwsh" -WorkingDirectory $wd -ArgumentList @('-noprofile','-command',$script)
79+
80+
Remove-Item -Path $wd -Force
81+
Remove-Item $lock
82+
$start = Get-Date
83+
84+
try {
85+
while ($null -eq (Get-Item "$testdrive/error" -ErrorAction Ignore) -and $null -eq (Get-Item "$testdrive/out" -ErrorAction Ignore)) {
86+
if (((Get-Date) - $start).TotalSeconds -gt 60) {
87+
throw "Timeout"
88+
}
89+
90+
Start-Sleep -Seconds 1
91+
}
92+
}
93+
finally {
94+
$pwsh | Stop-Process -Force -ErrorAction Ignore
95+
}
96+
97+
$err = Get-Item -Path "$testdrive/error" -ErrorAction Ignore
98+
$err | Should -BeNullOrEmpty -Because $err
99+
$out = Get-Item -Path "$testdrive/out" -ErrorAction Ignore
100+
$out | Should -Not -BeNullOrEmpty
101+
}
54102
}
55103

56104
Describe "Native Command Processor" -tags "Feature" {

0 commit comments

Comments
 (0)