diff --git a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs
index 2c43255cca4..d4e1ba033ef 100644
--- a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs
+++ b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs
@@ -1044,6 +1044,11 @@ private static string InternalGetFolderPath(SpecialFolder folder)
string folderPath = null;
#if UNIX
+ string envHome = System.Environment.GetEnvironmentVariable(Platform.CommonEnvVariableNames.Home);
+ if (null == envHome)
+ {
+ envHome = Platform.GetTemporaryDirectory();
+ }
switch (folder)
{
case SpecialFolder.ProgramFiles:
@@ -1060,11 +1065,22 @@ private static string InternalGetFolderPath(SpecialFolder folder)
if (!System.IO.Directory.Exists(folderPath)) { folderPath = null; }
break;
case SpecialFolder.Personal:
- folderPath = System.Environment.GetEnvironmentVariable("HOME");
+ folderPath = envHome;
break;
case SpecialFolder.LocalApplicationData:
- folderPath = System.IO.Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".config");
- if (!System.IO.Directory.Exists(folderPath)) { System.IO.Directory.CreateDirectory(folderPath); }
+ folderPath = System.IO.Path.Combine(envHome, ".config");
+ if (!System.IO.Directory.Exists(folderPath))
+ {
+ try
+ {
+ System.IO.Directory.CreateDirectory(folderPath);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ // directory creation may fail if the account doesn't have filesystem permission such as some service accounts
+ folderPath = String.Empty;
+ }
+ }
break;
default:
throw new NotSupportedException();
@@ -1100,7 +1116,7 @@ private static string InternalGetFolderPath(SpecialFolder folder)
}
break;
case SpecialFolder.MyDocuments: // same as SpecialFolder.Personal
- userProfile = System.Environment.GetEnvironmentVariable("USERPROFILE");
+ userProfile = System.Environment.GetEnvironmentVariable(Platform.CommonEnvVariableNames.Home);
if (userProfile != null)
{
folderPath = System.IO.Path.Combine(userProfile, "Documents");
@@ -1117,7 +1133,7 @@ private static string InternalGetFolderPath(SpecialFolder folder)
// It's guaranteed by NanoServer team that 'USERPROFILE' will be already set when SetupComplete.cmd runs.
// So we use the path '%USERPROFILE%\AppData\Local' as an alternative in this case, and also set the env
// variable %LOCALAPPDATA% to it, so that modules running in PS can depend on this env variable.
- userProfile = System.Environment.GetEnvironmentVariable("USERPROFILE");
+ userProfile = System.Environment.GetEnvironmentVariable(Platform.CommonEnvVariableNames.Home);
if (userProfile != null)
{
string alternatePath = System.IO.Path.Combine(userProfile, @"AppData\Local");
diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs
index bc558d053d6..d3f8cead66f 100644
--- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs
+++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs
@@ -16,6 +16,8 @@ namespace System.Management.Automation
///
public static class Platform
{
+ private static string _tempDirectory = null;
+
///
/// True if the current platform is Linux.
///
@@ -204,6 +206,41 @@ internal static class CommonEnvVariableNames
#endif
}
+ ///
+ /// Remove the temporary directory created for the current process
+ ///
+ internal static void RemoveTemporaryDirectory()
+ {
+ if (null == _tempDirectory)
+ {
+ return;
+ }
+
+ try
+ {
+ Directory.Delete(_tempDirectory, true);
+ }
+ catch
+ {
+ // ignore if there is a failure
+ }
+ _tempDirectory = null;
+ }
+
+ ///
+ /// Get a temporary directory to use for the current process
+ ///
+ internal static string GetTemporaryDirectory()
+ {
+ if (null != _tempDirectory)
+ {
+ return _tempDirectory;
+ }
+
+ _tempDirectory = PsUtils.GetTemporaryDirectory();
+ return _tempDirectory;
+ }
+
#if UNIX
///
/// X Desktop Group configuration type enum.
@@ -234,10 +271,15 @@ public static string SelectProductNameForDirectory(Platform.XDG_Type dirpath)
string xdgconfighome = System.Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
string xdgdatahome = System.Environment.GetEnvironmentVariable("XDG_DATA_HOME");
string xdgcachehome = System.Environment.GetEnvironmentVariable("XDG_CACHE_HOME");
- string xdgConfigHomeDefault = Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".config", "powershell");
- string xdgDataHomeDefault = Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".local", "share", "powershell");
+ string envHome = System.Environment.GetEnvironmentVariable(CommonEnvVariableNames.Home);
+ if (null == envHome)
+ {
+ envHome = GetTemporaryDirectory();
+ }
+ string xdgConfigHomeDefault = Path.Combine(envHome, ".config", "powershell");
+ string xdgDataHomeDefault = Path.Combine(envHome, ".local", "share", "powershell");
string xdgModuleDefault = Path.Combine(xdgDataHomeDefault, "Modules");
- string xdgCacheDefault = Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".cache", "powershell");
+ string xdgCacheDefault = Path.Combine(envHome, ".cache", "powershell");
switch (dirpath)
{
@@ -268,6 +310,7 @@ public static string SelectProductNameForDirectory(Platform.XDG_Type dirpath)
catch (UnauthorizedAccessException)
{
//service accounts won't have permission to create user folder
+ return GetTemporaryDirectory();
}
}
return xdgDataHomeDefault;
@@ -291,6 +334,7 @@ public static string SelectProductNameForDirectory(Platform.XDG_Type dirpath)
catch (UnauthorizedAccessException)
{
//service accounts won't have permission to create user folder
+ return GetTemporaryDirectory();
}
}
return xdgModuleDefault;
@@ -317,6 +361,7 @@ public static string SelectProductNameForDirectory(Platform.XDG_Type dirpath)
catch (UnauthorizedAccessException)
{
//service accounts won't have permission to create user folder
+ return GetTemporaryDirectory();
}
}
@@ -334,6 +379,7 @@ public static string SelectProductNameForDirectory(Platform.XDG_Type dirpath)
catch (UnauthorizedAccessException)
{
//service accounts won't have permission to create user folder
+ return GetTemporaryDirectory();
}
}
diff --git a/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs b/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs
index b218f1ea551..d9e295282ca 100644
--- a/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs
+++ b/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs
@@ -1267,6 +1267,8 @@ protected override void Dispose(bool disposing)
RunspaceOpening = null;
}
+ Platform.RemoveTemporaryDirectory();
+
// Dispose the event manager
if (this.ExecutionContext != null && this.ExecutionContext.Events != null)
{
diff --git a/src/System.Management.Automation/utils/PsUtils.cs b/src/System.Management.Automation/utils/PsUtils.cs
index 96a29ff2684..d764203da25 100644
--- a/src/System.Management.Automation/utils/PsUtils.cs
+++ b/src/System.Management.Automation/utils/PsUtils.cs
@@ -604,6 +604,30 @@ internal static bool IsRunningOnProcessorArchitectureARM()
#endif
}
+ ///
+ /// Get a temporary directory to use, needs to be unique to avoid collision
+ ///
+ internal static string GetTemporaryDirectory()
+ {
+ string tempDir = String.Empty;
+ string tempPath = Path.GetTempPath();
+ do
+ {
+ tempDir = Path.Combine(tempPath,System.Guid.NewGuid().ToString());
+ }
+ while (Directory.Exists(tempDir));
+
+ try
+ {
+ Directory.CreateDirectory(tempDir);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ tempDir = String.Empty; // will become current working directory
+ }
+ return tempDir;
+ }
+
internal static string GetHostName()
{
// Note: non-windows CoreCLR does not support System.Net yet
diff --git a/test/powershell/Host/ConsoleHost.Tests.ps1 b/test/powershell/Host/ConsoleHost.Tests.ps1
index 000bbf86103..aafb0b2649f 100644
--- a/test/powershell/Host/ConsoleHost.Tests.ps1
+++ b/test/powershell/Host/ConsoleHost.Tests.ps1
@@ -403,6 +403,12 @@ foo
[int]$output | Should BeGreaterThan 0
}
}
+
+ Context "HOME environment variable" {
+ It "Should start if HOME is not defined" -skip:($IsWindows) {
+ bash -c "unset HOME;$powershell -c '1+1'" | Should BeExactly 2
+ }
+ }
}
Describe "Console host api tests" -Tag CI {