Skip to content

Commit 5f00798

Browse files
committed
Add experimental feature check and add PSContentPath to standard platform paths
1 parent b85a9a8 commit 5f00798

1 file changed

Lines changed: 143 additions & 4 deletions

File tree

src/code/Utils.cs

Lines changed: 143 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,14 +1049,14 @@ public static List<string> GetPathsFromEnvVarAndScope(
10491049
{
10501050
GetStandardPlatformPaths(
10511051
psCmdlet,
1052-
out string myDocumentsPath,
1052+
out string psUserContentPath,
10531053
out string programFilesPath);
10541054

10551055
List<string> resourcePaths = new List<string>();
10561056
if (scope is null || scope.Value is ScopeType.CurrentUser)
10571057
{
1058-
resourcePaths.Add(Path.Combine(myDocumentsPath, "Modules"));
1059-
resourcePaths.Add(Path.Combine(myDocumentsPath, "Scripts"));
1058+
resourcePaths.Add(Path.Combine(psUserContentPath, "Modules"));
1059+
resourcePaths.Add(Path.Combine(psUserContentPath, "Scripts"));
10601060
}
10611061

10621062
if (scope.Value is ScopeType.AllUsers)
@@ -1156,6 +1156,112 @@ private static string GetHomeOrCreateTempHome()
11561156
}
11571157

11581158
private readonly static Version PSVersion6 = new Version(6, 0);
1159+
1160+
/// <summary>
1161+
/// Checks if a PowerShell experimental feature is enabled by reading the PowerShell configuration file.
1162+
/// Returns false if the configuration file doesn't exist or if the feature is not enabled.
1163+
/// </summary>
1164+
private static bool IsExperimentalFeatureEnabled(PSCmdlet psCmdlet, string featureName)
1165+
{
1166+
try
1167+
{
1168+
// PowerShell configuration file location
1169+
string configPath = Path.Combine(
1170+
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
1171+
"powershell",
1172+
"powershell.config.json"
1173+
);
1174+
1175+
if (!File.Exists(configPath))
1176+
{
1177+
psCmdlet.WriteVerbose("PowerShell configuration file not found, experimental features not enabled");
1178+
return false;
1179+
}
1180+
1181+
string jsonContent = File.ReadAllText(configPath);
1182+
1183+
// Parse JSON to check for experimental features
1184+
// Look for "ExperimentalFeatures": ["FeatureName"] in the config
1185+
if (jsonContent.Contains($"\"{featureName}\""))
1186+
{
1187+
psCmdlet.WriteVerbose(string.Format("Experimental feature '{0}' found in configuration file", featureName));
1188+
return true;
1189+
}
1190+
1191+
psCmdlet.WriteVerbose(string.Format("Experimental feature '{0}' not found in configuration file", featureName));
1192+
return false;
1193+
}
1194+
catch (Exception ex)
1195+
{
1196+
psCmdlet.WriteVerbose(string.Format("Error reading PowerShell configuration file: {0}", ex.Message));
1197+
return false;
1198+
}
1199+
}
1200+
1201+
/// <summary>
1202+
/// Gets the custom PSUserContentPath from environment variable or PowerShell configuration file.
1203+
/// Environment variable takes precedence over the configuration file setting.
1204+
/// Returns null if neither is set or configured.
1205+
/// </summary>
1206+
private static string GetPSUserContentPath(PSCmdlet psCmdlet)
1207+
{
1208+
try
1209+
{
1210+
// First check the environment variable (takes precedence)
1211+
string envPSUserContentPath = Environment.GetEnvironmentVariable("PSUserContentPath");
1212+
if (!string.IsNullOrEmpty(envPSUserContentPath))
1213+
{
1214+
psCmdlet.WriteVerbose(string.Format("Found PSUserContentPath from environment variable: {0}", envPSUserContentPath));
1215+
return envPSUserContentPath;
1216+
}
1217+
1218+
// If environment variable not set, check the configuration file
1219+
string configPath = Path.Combine(
1220+
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
1221+
"powershell",
1222+
"powershell.config.json"
1223+
);
1224+
1225+
if (!File.Exists(configPath))
1226+
{
1227+
psCmdlet.WriteVerbose("PowerShell configuration file not found");
1228+
return null;
1229+
}
1230+
1231+
string jsonContent = File.ReadAllText(configPath);
1232+
1233+
// Simple JSON parsing to find PSUserContentPath
1234+
// Format: "PSUserContentPath": "C:\\CustomPath"
1235+
int userPathIndex = jsonContent.IndexOf("\"PSUserContentPath\"", StringComparison.OrdinalIgnoreCase);
1236+
if (userPathIndex >= 0)
1237+
{
1238+
int colonIndex = jsonContent.IndexOf(':', userPathIndex);
1239+
if (colonIndex >= 0)
1240+
{
1241+
int firstQuote = jsonContent.IndexOf('"', colonIndex + 1);
1242+
int secondQuote = jsonContent.IndexOf('"', firstQuote + 1);
1243+
1244+
if (firstQuote >= 0 && secondQuote > firstQuote)
1245+
{
1246+
string customPath = jsonContent.Substring(firstQuote + 1, secondQuote - firstQuote - 1);
1247+
// Unescape JSON string (handle \\)
1248+
customPath = customPath.Replace("\\\\", "\\");
1249+
psCmdlet.WriteVerbose(string.Format("Found PSUserContentPath in config file: {0}", customPath));
1250+
return customPath;
1251+
}
1252+
}
1253+
}
1254+
1255+
psCmdlet.WriteVerbose("PSUserContentPath not configured in PowerShell configuration file or environment variable");
1256+
return null;
1257+
}
1258+
catch (Exception ex)
1259+
{
1260+
psCmdlet.WriteVerbose(string.Format("Error reading PSUserContentPath: {0}", ex.Message));
1261+
return null;
1262+
}
1263+
}
1264+
11591265
private static void GetStandardPlatformPaths(
11601266
PSCmdlet psCmdlet,
11611267
out string localUserDir,
@@ -1164,7 +1270,40 @@ private static void GetStandardPlatformPaths(
11641270
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
11651271
{
11661272
string powerShellType = (psCmdlet.Host.Version >= PSVersion6) ? "PowerShell" : "WindowsPowerShell";
1167-
localUserDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType);
1273+
1274+
// Check if PSContentPath experimental feature is enabled
1275+
bool usePSContentPath = IsExperimentalFeatureEnabled(psCmdlet, "PSContentPath");
1276+
1277+
if (usePSContentPath)
1278+
{
1279+
psCmdlet.WriteVerbose("PSContentPath experimental feature is enabled");
1280+
1281+
// Check environment variable and config file for custom PSUserContentPath
1282+
string customPSUserContentPath = GetPSUserContentPath(psCmdlet);
1283+
1284+
if (!string.IsNullOrEmpty(customPSUserContentPath) && Directory.Exists(customPSUserContentPath))
1285+
{
1286+
// Use custom configured path
1287+
localUserDir = customPSUserContentPath;
1288+
psCmdlet.WriteVerbose($"Using custom PSUserContentPath: {localUserDir}");
1289+
}
1290+
else
1291+
{
1292+
// Use default LocalApplicationData location when PSContentPath is enabled
1293+
localUserDir = Path.Combine(
1294+
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
1295+
powerShellType
1296+
);
1297+
psCmdlet.WriteVerbose($"Using default PSContentPath location: {localUserDir}");
1298+
}
1299+
}
1300+
else
1301+
{
1302+
// PSContentPath not enabled, use legacy Documents folder
1303+
localUserDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), powerShellType);
1304+
psCmdlet.WriteVerbose($"Using legacy Documents folder: {localUserDir}");
1305+
}
1306+
11681307
allUsersDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), powerShellType);
11691308
}
11701309
else

0 commit comments

Comments
 (0)