Skip to content

[Az.Accounts] Fix access denied on config init mutex when importing under different users - #30340

Open
Leon Zandman (lzandman) wants to merge 4 commits into
Azure:mainfrom
lzandman:fix/accounts-config-init-mutex-25701
Open

Leon Zandman (lzandman) wants to merge 4 commits into
Azure:mainfrom
lzandman:fix/accounts-config-init-mutex-25701

Conversation

@lzandman

@lzandman Leon Zandman (lzandman) commented Oct 23, 2026 •

Copy link
Copy Markdown

🤖 PR Validation — ⚠️ Review suggested

Tests Suppressions
⚠️ 106/106 ️✔️ None
⚠️Az.Accounts
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Breaking Change Check
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Signature Check
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Help File Existence Check
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️File Change Check
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
⚠️UX Metadata Check
⚠️PowerShell Core - Windows
Type Module ResourceType SubResourceType Command Description
⚠️ Az.Accounts Microsoft.Subscription subscriptions Get-AzSubscription The path /subscriptions/{subscriptionId} doesn't contains the right resource tpye: Microsoft.Subscription
⚠️Windows PowerShell - Windows
Type Module ResourceType SubResourceType Command Description
⚠️ Az.Accounts Microsoft.Subscription subscriptions Get-AzSubscription The path /subscriptions/{subscriptionId} doesn't contains the right resource tpye: Microsoft.Subscription
️✔️Test
️✔️PowerShell Core - Linux
️✔️PowerShell Core - MacOS
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Az.Aks
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Test
️✔️PowerShell Core - Linux
️✔️PowerShell Core - MacOS
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
⚠️Az.ApplicationInsights
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
⚠️Test
⚠️PowerShell Core - Linux
Type Title Current Coverage Last Coverage Description
⚠️ Test Coverage Less Than 80% 54.05 % 64.86% Test coverage cannot be lower than the number of the last release.
⚠️PowerShell Core - MacOS
Type Title Current Coverage Last Coverage Description
⚠️ Test Coverage Less Than 80% 54.05% 64.86% Test coverage cannot be lower than the number of the last release.
⚠️PowerShell Core - Windows
Type Title Current Coverage Last Coverage Description
⚠️ Test Coverage Less Than 80% 54.05% 64.86% Test coverage cannot be lower than the number of the last release.
⚠️Windows PowerShell - Windows
Type Title Current Coverage Last Coverage Description
⚠️ Test Coverage Less Than 80% 54.05% 64.86% Test coverage cannot be lower than the number of the last release.
️✔️Az.Compute
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Test
️✔️PowerShell Core - Linux
️✔️PowerShell Core - MacOS
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Az.Functions
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Test
️✔️PowerShell Core - Linux
️✔️PowerShell Core - MacOS
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
⚠️Az.KeyVault
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
⚠️Test
⚠️PowerShell Core - Linux
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 25.56 % Test coverage for the module cannot be lower than 50%.
⚠️PowerShell Core - MacOS
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 25.56% Test coverage for the module cannot be lower than 50%.
⚠️PowerShell Core - Windows
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 25.56% Test coverage for the module cannot be lower than 50%.
⚠️Windows PowerShell - Windows
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 25.56% Test coverage for the module cannot be lower than 50%.
️✔️Az.KubernetesConfiguration
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Test
️✔️PowerShell Core - Linux
️✔️PowerShell Core - MacOS
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Az.ManagedServiceIdentity
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Az.Monitor
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Az.Network
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Test
️✔️PowerShell Core - Linux
️✔️PowerShell Core - MacOS
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Az.OperationalInsights
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Az.PrivateDns
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
⚠️Az.Purview
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
⚠️Test
⚠️PowerShell Core - Linux
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 8.20 % Test coverage for the module cannot be lower than 50%.
⚠️PowerShell Core - MacOS
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 8.20% Test coverage for the module cannot be lower than 50%.
⚠️PowerShell Core - Windows
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 8.20% Test coverage for the module cannot be lower than 50%.
⚠️Windows PowerShell - Windows
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 8.20% Test coverage for the module cannot be lower than 50%.
⚠️Az.RedHatOpenShiftHcp
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Breaking Change Check
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Signature Check
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Help Example Check
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Help File Existence Check
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
⚠️File Change Check
⚠️PowerShell Core - Windows
Type Cmdlet Description Remediation
⚠️ AssemblyInfo.cs will be updated automatically. Please do not update it manually. Revert AssemblyInfo.cs to its last version.
⚠️Windows PowerShell - Windows
Type Cmdlet Description Remediation
⚠️ AssemblyInfo.cs will be updated automatically. Please do not update it manually. Revert AssemblyInfo.cs to its last version.
️✔️UX Metadata Check
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Az.Resources
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Test
️✔️PowerShell Core - Linux
️✔️PowerShell Core - MacOS
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Az.Sql
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
⚠️Az.Storage
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
⚠️Test
⚠️PowerShell Core - Linux
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 43.96 % Test coverage for the module cannot be lower than 50%.
⚠️PowerShell Core - MacOS
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 43.96% Test coverage for the module cannot be lower than 50%.
⚠️PowerShell Core - Windows
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 43.96% Test coverage for the module cannot be lower than 50%.
⚠️Windows PowerShell - Windows
Type Title Current Coverage Description
⚠️ Test Coverage Less Than 50% 43.96% Test coverage for the module cannot be lower than 50%.
️✔️Az.Websites
️✔️Build
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows
️✔️Test
️✔️PowerShell Core - Linux
️✔️PowerShell Core - MacOS
️✔️PowerShell Core - Windows
️✔️Windows PowerShell - Windows

Description

Fixes #25701: Import-Module Az.Accounts fails with Access to the path 'Global\AzurePowerShellConfigInit' is denied when processes run by different users (e.g. multiple DevOps agents or scheduled tasks on one machine) import the module concurrently.

Root cause

AzureSessionInitializer.InitializeConfigs creates a machine-wide named mutex without explicit security. Windows gives it the default DACL of the creating process, so while it exists, a process running as another principal cannot open it and the Mutex constructor throws. The constructor sits outside any try, so the whole module import fails.

The lock protects PSConfig.json in the current user's profile, so different users never need to share it.

Changes

  • The mutex name is now derived from the config file path (Global\AzurePowerShellConfigInit_<hash>, where the hash is the first 16 bytes of the SHA-256 of the upper-cased path, as 32 hex characters). Processes of the same user still share the lock, but different users no longer collide. 128 bits is far more than needed to tell apart the few user profiles on one machine, and keeps the name readable in tools such as Process Explorer.
  • If the mutex still cannot be opened (e.g. another process of the same user created it with a DACL this process isn't granted), the module now logs a warning and initializes configs in safe mode, which matches the existing timeout path, instead of failing the import.
  • AbandonedMutexException from WaitOne is treated as a successful acquire, so the next process can still initialize configs if a previous one crashed while holding the lock.

Compatibility

For a single user, behaviour is unchanged: processes share one lock with the same 1 s timeout and the same safe-mode fallback. Because the lock name changed, an older and a newer Az.Accounts version running side by side for the same user no longer share a lock. The worst case is that both initialize configs at once, which is what already happens today when the timeout expires. When an abandoned lock is acquired, a config file left half-written by the crashed owner is handled by the existing try/catch around initialization, which falls back to safe mode.

Explicit mutex ACLs (MutexAcl) were considered but not used. They are Windows-only, do not help against mutexes created by older versions, and .NET Framework's Mutex constructor would require granting Everyone full control.

Tests

Added unit tests to SessionInitializationTests covering the mutex name scoping and acquiring an abandoned mutex.

Also tested manually on Windows 11 (PowerShell 7.6 and Windows PowerShell 5.1), comparing Az.Accounts 5.5.3 from the Gallery with a build of this branch. Each user ran in a separate logon session (SSH), like separate DevOps agents:

  • Repro: while another user holds Global\AzurePowerShellConfigInit, 5.5.3 fails with the access-denied error. The fixed build imports normally.
  • Concurrency: two users each importing 100 times at the same moment: 0 failures with the fix (5.5.3: 1 of 200 failed with the original error). One user on 5.5.3 and another on the fix at the same time: 0 failures.
  • Fallback: when the lock can't be opened (an elevated process holds it with an Administrators-only DACL), the fixed build imports in safe mode with a warning. 5.5.3 fails.
  • Unchanged behaviour: a lock held by the same user still gives safe mode after the 1 s timeout. An abandoned lock is acquired and configs initialize normally.

On macOS (PowerShell 7.6) the unit tests, timeout and abandoned-mutex scenarios pass as well. macOS can't show the cross-user fix, because .NET emulates named mutexes with files there.

Mandatory Checklist

  • SHOULD update ChangeLog.md file(s) appropriately
    • Update src/{{SERVICE}}/{{SERVICE}}/ChangeLog.md.
      • A snippet outlining the change(s) made in the PR should be written under the ## Upcoming Release header in the past tense.
    • Should not change ChangeLog.md if no new release is required, such as fixing test case only.
  • SHOULD regenerate markdown help files if there is cmdlet API change. Instruction
  • SHOULD have proper test coverage for changes in pull request.
  • SHOULD NOT adjust version of module manually in pull request

…nder different users

Fixes Azure#25701.

Config initialization was guarded by a single machine-wide mutex,
Global\AzurePowerShellConfigInit. Once a process running as one user
created it, processes running as other users could not open it, and
importing the module failed with "Access to the path
'Global\AzurePowerShellConfigInit' is denied".

The config file lives in the user's profile, so the lock only has to be
shared by processes of the same user. Derive the mutex name from a hash
of the config file path so users no longer collide. If the mutex still
cannot be opened, warn and fall back to safe-mode initialization instead
of failing the import. An abandoned mutex is now treated as acquired,
since ownership passes to the waiting thread.
Copilot AI balanced review requested due to automatic review settings October 23, 2026 20:23
@azure-pipelines

Copy link
Copy Markdown
Contributor
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@microsoft-github-policy-service

Copy link
Copy Markdown
Contributor

Thank you for your contribution Leon Zandman (@lzandman)! We will review the pull request and get back to you soon.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Source review identified no blocking issues in the focused mutex changes; tests were not executed during this review.

No open issues 🎉

What changed in this PR

Fixes #25701 by isolating Az.Accounts configuration initialization locks by config path, preventing cross-user mutex access conflicts during concurrent imports.

Changes:

  • Replaces the machine-wide shared lock name with a config-path-derived name.
  • Falls back to safe mode when the lock cannot be opened and handles abandoned mutexes as acquired.
  • Adds focused unit tests and user-facing release notes.
File Description
src/​Accounts/​Authentication/​AzureSessionInitializer.cs Scopes mutex names and handles lock failures and abandonment.
src/​Accounts/​Authentication.Test/​SessionInitializationTests.cs Tests path-scoped names and abandoned-mutex acquisition.
src/​Accounts/​Accounts/​ChangeLog.md Documents the import fix and safe-mode fallback.

Review effort: Balanced

@NoriZC

NoriZC commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Contributor
Azure Pipelines:
Successfully started running 3 pipeline(s).

Copilot AI balanced review requested due to automatic review settings October 26, 2026 08:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused changes preserve timeout and cleanup behavior, with unit tests and reported cross-user validation supporting approval.

No open issues 🎉

Review effort: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mutex fail: Access to the path 'Global\AzurePowerShellConfigInit' is denied.

5 participants