Tolerate IO/JSON errors reading the per-user powershell.config.json#27373
Open
jshigetomi wants to merge 4 commits intoPowerShell:masterfrom
Open
Tolerate IO/JSON errors reading the per-user powershell.config.json#27373jshigetomi wants to merge 4 commits intoPowerShell:masterfrom
powershell.config.json#27373jshigetomi wants to merge 4 commits intoPowerShell:masterfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates PowerShell’s configuration loading so unreadable/malformed per-user powershell.config.json no longer prevents startup: it falls back to defaults and emits a warning, while system-wide config failures remain fatal for security reasons.
Changes:
- Added exception handling for
ConfigScope.CurrentUserconfig reads to fail open (with a warning) on IO/permission/JSON errors. - Introduced a new localized warning string for unreadable per-user config.
- Added/updated xUnit coverage to validate fail-open for per-user config and fail-closed for system-wide config.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/System.Management.Automation/engine/PSConfiguration.cs |
Adds per-user config fail-open exception handling and warning emission during config root load. |
src/System.Management.Automation/resources/PSConfigurationStrings.resx |
Adds localized warning text for unreadable per-user config. |
test/xUnit/csharp/test_PSConfiguration.cs |
Adds fixture helper and tests to validate per-user fallback vs system-wide failure behavior. |
- Wrap jToken.ToObject<T>(serializer) in try/catch that fail-opens for ConfigScope.CurrentUser on JsonException. Addresses Copilot review feedback on PR PowerShell#27373: a syntactically valid per-user powershell.config.json with a wrong-typed value (e.g. PowerShellPolicies.ScriptExecution as a string) would still crash startup via JsonSerializationException. AllUsers stays fail-closed. - Add SecurityException to the file-open catch filter so an ACL/policy denial on the per-user file behaves the same as UnauthorizedAccessException. - Add CanNotReadConfigurationValue resource string for the per-key warning. - Add PowerShellConfig_TypeMismatchInCurrentUserConfig_FallsBackToDefaults xUnit test, with a fixture helper that writes valid JSON containing a nested wrong shape. Refs PowerShell#27370 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addresses five Copilot review comments on PR PowerShell#27373: 1. Extract TryWriteConfigWarning helper to centralize the best-effort warning emission. Both fallback paths now call this helper instead of duplicating try/catch around Console.Error.WriteLine. 2. Document why Console.Error is the right channel here: ReadValueFromFile runs very early in pwsh startup (before any host, runspace, or warning stream exists). The helper provides a single seam for future hosts to redirect. This matches existing startup-time stderr writes in ConsoleHost.cs (e.g. CannotLoadPSReadline, SlowProfileLoadingMessage). 3. Remove the literal 'WARNING:' prefix from the localized resource strings; the helper prepends it. This keeps the resource content prefix-free for future routing through the warning stream. 4. Rename PowerShellConfig_GetPowerShellPolicies_BrokenSystemConfig to PowerShellConfig_BrokenSystemConfig_Throws_BrokenCurrentUserConfig_FallsBack to make the dual fail-closed/fail-open assertions explicit. 5. Add two new xUnit tests that capture Console.Error and assert the warning is actually emitted (not silently dropped): - PowerShellConfig_BrokenCurrentUserConfig_EmitsWarningToStderr - PowerShellConfig_TypeMismatchInCurrentUserConfig_EmitsWarningToStderr Refs PowerShell#27370 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Summary
This pull request improves how PowerShell handles unreadable or malformed per-user configuration files. Instead of failing to start, PowerShell now falls back to default settings and emits a warning when the per-user config is unreadable, while maintaining strict failure for system-wide config issues. This addresses a startup-time crash caused by transient cloud file provider failures (e.g., OneDrive not yet running on a fresh login). The PR also adds new tests to verify this behavior.
Configuration file handling improvements:
PSConfiguration.csso the per-user (ConfigScope.CurrentUser) config read fails open in two places:IOException,UnauthorizedAccessException,SecurityException, andJsonException(including the OneDrive-cloud-file-provider IOException that motivated PS7 should revert to defaults if it can't load user powershell.config.json #27370).PowerShellPolicies.ScriptExecutionis a string instead of an object). CatchesJsonException/JsonSerializationExceptionfromjToken.ToObject<T>(serializer)so a single malformed setting doesn't crash startup.TryWriteConfigWarninghelper that writes a best-effort warning toConsole.Error.Console.Erroris intentional at this layer:ReadValueFromFileruns very early in startup, before any host, runspace, or PowerShell warning stream exists. This matches existing startup-time stderr writes inConsoleHost.cs(e.g.,CannotLoadPSReadline,SlowProfileLoadingMessage). Centralizing the call gives future hosts a single seam to swap the channel.ConfigScope.AllUsers) config file, which remains a hard failure for security reasons (admin-owned, sole source of security-relevant policies on non-Windows).PSConfigurationStrings.resx:CanNotReadConfigurationFile— for the file-level fallback.CanNotReadConfigurationValue— for the per-key fallback.WARNING:label so the resource content stays usable if a future host routes these through the warning stream.Testing enhancements:
test_PSConfiguration.cs:SetupBrokenCurrentUserConfigOnly— broken per-user config, no system config (file-level path).SetupTypeMismatchedCurrentUserConfig— valid JSON with a wrong nested shape (per-key path).CaptureStderr(Action)helper that redirectsConsole.Errorso tests can assert the warning was actually emitted.PowerShellConfig_BrokenSystemConfig_Throws_BrokenCurrentUserConfig_FallsBack(renamed fromPowerShellConfig_GetPowerShellPolicies_BrokenSystemConfig) — asserts both fail-closed forAllUsersand fail-open forCurrentUser.PowerShellConfig_BrokenCurrentUserConfig_FallsBackToDefaults— broken per-user file returns defaults viaGetExecutionPolicy,GetModulePath,GetExperimentalFeatures.PowerShellConfig_TypeMismatchInCurrentUserConfig_FallsBackToDefaults— valid JSON with a type-mismatched value returns null instead of throwing.PowerShellConfig_BrokenCurrentUserConfig_EmitsWarningToStderr— pins that the file-level warning is actually written.PowerShellConfig_TypeMismatchInCurrentUserConfig_EmitsWarningToStderr— pins that the per-key warning is actually written.PR Context
Fixes #27370
The original report showed pwsh hard-failing at startup with
IOException: The cloud file provider is not runningwhen the user'spowershell.config.jsonlives in a OneDrive-syncedDocuments\PowerShellfolder and OneDrive hasn't started yet. The same code path also blew up on permission-denied and corrupt-JSON cases. After this PR, all of those scenarios warn to stderr and fall back to default settings (so$profile, execution policy, module path, etc. work as if the file were absent), while the admin-ownedAllUsersconfig still fails closed.PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright header