Mutex.psm1
function Get-Mutex { <# .SYNOPSIS Get currently defined Mutexes. .DESCRIPTION Get currently defined Mutexes. Only returns mutexes owned and managed by this module. .PARAMETER Name Name of the mutex to retrieve. Supports wildcards, defaults to '*' .EXAMPLE PS C:\> Get-Mutex Return all mutexes. .EXAMPLE PS C:\> Get-Mutex -Name MyModule.LogFile Returns the mutex named "MyModule.LogFile" #> [CmdletBinding()] Param ( [string] $Name = '*' ) process { $script:mutexes.Values | Where-Object Name -like $Name } } function Lock-Mutex { <# .SYNOPSIS Acquire a lock on a mutex. .DESCRIPTION Acquire a lock on a mutex. Implicitly calls New-Mutex if the mutex hasn't been taken under the management of the current process yet. .PARAMETER Name Name of the mutex to acquire a lock on. .PARAMETER Timeout How long to wait for acquiring the mutex, before giving up with an error. .EXAMPLE PS C:\> Lock-Mutex -Name MyModule.LogFile Acquire a lock on the mutex 'MyModule.LogFile' #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Name, [timespan] $Timeout ) process { foreach ($mutexName in $Name) { if (-not $script:mutexes[$mutexName]) { New-Mutex -Name $mutexName } if (-not $Timeout) { $script:mutexes[$mutexName].Object.WaitOne() } else { try { $script:mutexes[$mutexName].Object.WaitOne($Timeout) } catch { Write-Error $_ continue } } $script:mutexes[$mutexName].Status = 'Locked' } } } function New-Mutex { <# .SYNOPSIS Create a new mutex managed by this module. .DESCRIPTION Create a new mutex managed by this module. The mutex is created in an unacquired state. Use Lock-Mutex to acquire the mutex. Note: Calling Lock-Mutex without first calling New-Mutex will implicitly call New-Mutex. .PARAMETER Name Name of the mutex to create. The name is what the system selects for when marshalling access: All mutexes with the same name block each other, across all processes on the current host. .EXAMPLE PS C:\> New-Mutex -Name MyModule.LogFile Create a new, unlocked mutex named 'MyModule.LogFile' #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [string] $Name ) process { if ($script:mutexes[$Name]) { return } $script:mutexes[$Name] = [PSCustomObject]@{ Name = $Name Status = "Open" Object = [System.Threading.Mutex]::new($false, $Name) } } } function Remove-Mutex { <# .SYNOPSIS Removes a mutex from the list of available mutexes. .DESCRIPTION Removes a mutex from the list of available mutexes. Only affects mutexes owned and managed by this module. Will silently return on unknown mutexes, not throw an error. .PARAMETER Name Name of the mutex to remove. Must be an exact, case-insensitive match. .EXAMPLE PS C:\> Get-Mutex | Remove-Mutex Clear all mutex owned by the current runspace managed by this module. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] Param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Name ) process { foreach ($mutexName in $Name) { if (-not $script:mutexes[$mutexName]) { continue } Unlock-Mutex -Name $mutexName $script:mutexes.Remove($mutexName) } } } function Unlock-Mutex { <# .SYNOPSIS Release the lock on a mutex you manage. .DESCRIPTION Release the lock on a mutex you manage. Will silently return if the mutex does not exist. .PARAMETER Name The name of the mutex to release the lock on. .EXAMPLE PS C:\> Unlock-Mutex -Name MyModule.LogFile Release the lock on the mutex 'MyModule.LogFile' .EXAMPLE PS C:\> Get-Mutex | Release-Mutex Release the lock on all mutexes managed. #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string] $Name ) process { foreach ($mutexName in $Name) { if (-not $script:mutexes[$mutexName]) { return } if ($script:mutexes[$mutexName].Status -eq "Open") { return } $script:mutexes[$mutexName].Object.ReleaseMutex() $script:mutexes[$mutexName].Status = 'Open' } } } # Central list of all mutexes $script:mutexes = @{ } |