diff --git a/src/code/Utils.cs b/src/code/Utils.cs index ae540f9e4..d8b61757f 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -22,6 +22,7 @@ using Azure.Identity; using System.Text.RegularExpressions; using System.Threading; +using System.Text.Json; using System.Threading.Tasks; using System.Xml; @@ -1049,14 +1050,14 @@ public static List GetPathsFromEnvVarAndScope( { GetStandardPlatformPaths( psCmdlet, - out string myDocumentsPath, + out string psUserContentPath, out string programFilesPath); List resourcePaths = new List(); if (scope is null || scope.Value is ScopeType.CurrentUser) { - resourcePaths.Add(Path.Combine(myDocumentsPath, "Modules")); - resourcePaths.Add(Path.Combine(myDocumentsPath, "Scripts")); + resourcePaths.Add(Path.Combine(psUserContentPath, "Modules")); + resourcePaths.Add(Path.Combine(psUserContentPath, "Scripts")); } if (scope.Value is ScopeType.AllUsers) @@ -1156,28 +1157,103 @@ private static string GetHomeOrCreateTempHome() } private readonly static Version PSVersion6 = new Version(6, 0); + private readonly static Version PSVersion7_7 = new Version(7, 7); + + /// + /// Gets the user content directory path using PowerShell's Get-PSContentPath cmdlet. + /// Falls back to legacy path if the cmdlet is not available or PowerShell version is below 7.7.0. + /// + private static string GetUserContentPath(PSCmdlet psCmdlet, Version psVersion, string legacyPath) + { + + // Only use Get-PSContentPath cmdlet if PowerShell version is 7.7.0 or greater (when PSContentPath feature is available) + if (psVersion >= PSVersion7_7) + { + // Try to use PowerShell's Get-PSContentPath cmdlet in the current runspace + // This cmdlet is only available if experimental feature PSContentPath is enabled + try + { + var results = psCmdlet.InvokeCommand.InvokeScript("Get-PSContentPath"); + + if (results != null && results.Count > 0) + { + // Get-PSContentPath returns a PSObject, extract the path string + string userContentPath = results[0]?.ToString(); + if (!string.IsNullOrEmpty(userContentPath)) + { + psCmdlet.WriteVerbose($"User content path from Get-PSContentPath: {userContentPath}"); + return userContentPath; + } + } + } + catch (Exception ex) + { + psCmdlet.WriteVerbose($"Get-PSContentPath cmdlet not available: {ex.Message}"); + } + } + else + { + psCmdlet.WriteVerbose($"PowerShell version {psVersion} is below 7.7.0, using legacy location"); + } + + // Fallback to legacy location + psCmdlet.WriteVerbose($"Using legacy location: {legacyPath}"); + return legacyPath; + } + private static void GetStandardPlatformPaths( PSCmdlet psCmdlet, out string localUserDir, out string allUsersDir) { + // Get PowerShell engine version from $PSVersionTable.PSVersion + Version psVersion = new Version(5, 1); + try + { + dynamic psVersionObj = (psCmdlet.SessionState.PSVariable.GetValue("PSVersionTable") as Hashtable)?["PSVersion"]; + if (psVersionObj != null) psVersion = new Version((int)psVersionObj.Major, (int)psVersionObj.Minor); + } + catch { + // Fallback if dynamic access fails + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - string powerShellType = (psCmdlet.Host.Version >= PSVersion6) ? "PowerShell" : "WindowsPowerShell"; - localUserDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType); + string powerShellType = (psVersion >= PSVersion6) ? "PowerShell" : "WindowsPowerShell"; + + // Windows PowerShell doesn't support experimental features or PSContentPath + if (powerShellType == "WindowsPowerShell") + { + // Use legacy Documents folder for Windows PowerShell + localUserDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType); + psCmdlet.WriteVerbose($"Using Windows PowerShell Documents folder: {localUserDir}"); + } + else + { + string legacyPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), + powerShellType + ); + + localUserDir = GetUserContentPath(psCmdlet, psVersion, legacyPath); + } + allUsersDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), powerShellType); } else { // paths are the same for both Linux and macOS - localUserDir = Path.Combine(GetHomeOrCreateTempHome(), ".local", "share", "powershell"); - // Create the default data directory if it doesn't exist. + string legacyPath = Path.Combine(GetHomeOrCreateTempHome(), ".local", "share", "powershell"); + + localUserDir = GetUserContentPath(psCmdlet, psVersion, legacyPath); + + // Create the default data directory if it doesn't exist if (!Directory.Exists(localUserDir)) { Directory.CreateDirectory(localUserDir); } - allUsersDir = System.IO.Path.Combine("/usr", "local", "share", "powershell"); + allUsersDir = Path.Combine("/usr", "local", "share", "powershell"); } }