@@ -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