private/functions/Enter-PowerStubConfigurationLock.ps1

<#
.SYNOPSIS
  Acquires the cross-process configuration lock.

.DESCRIPTION
  Serializes access to the configuration file across all PowerShell sessions using
  a named mutex derived from the config file path. The lock is re-entrant, so code
  holding it may call other functions that take it again.

  Always release with Exit-PowerStubConfigurationLock in a finally block.

.INPUTS
None. You cannot pipe objects to this function.

.OUTPUTS
System.Threading.Mutex. The held lock, to pass to Exit-PowerStubConfigurationLock.
#>



function Enter-PowerStubConfigurationLock {
    [CmdletBinding()]
    param ()

    $fileName = Get-PowerStubConfigurationKey 'ConfigFile'

    $hashAlgorithm = [System.Security.Cryptography.SHA256]::Create()
    $pathBytes = [System.Text.Encoding]::UTF8.GetBytes([System.IO.Path]::GetFullPath($fileName).ToUpperInvariant())
    $hash = [System.BitConverter]::ToString($hashAlgorithm.ComputeHash($pathBytes)).Replace('-', '')
    $hashAlgorithm.Dispose()

    $mutex = [System.Threading.Mutex]::new($false, "PowerStubConfig-$hash")
    try {
        $lockTaken = $mutex.WaitOne([TimeSpan]::FromSeconds(10))
    }
    catch [System.Threading.AbandonedMutexException] {
        # The previous owner died without releasing; the lock is ours now.
        $lockTaken = $true
    }

    if (-not $lockTaken) {
        $mutex.Dispose()
        throw "Timed out waiting for the PowerStub configuration lock for '$fileName'."
    }

    return $mutex
}