$hashTable = @{}
Lock-Object -InputObject $hashTable.SyncRoot -ScriptBlock {
$hashTable.Add("Key", "Value")
}
function Lock-Object
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0)]
[AllowEmptyString()]
[AllowEmptyCollection()]
[object]
$InputObject,
[Parameter(Mandatory = $true, Position = 1)]
[scriptblock]
$ScriptBlock
)
# Since we're dot-sourcing the caller's script block, we'll use Private scoped variables within this function to make sure
# the script block doesn't do anything fishy (like changing our InputObject or lockTaken values before we get a chance to
# release the lock.)
Set-Variable -Scope Private -Name __inputObject -Value $InputObject -Option ReadOnly -Force
Set-Variable -Scope Private -Name __scriptBlock -Value $ScriptBlock -Option ReadOnly -Force
Set-Variable -Scope Private -Name __threadID -Value ([System.Threading.Thread]::CurrentThread.ManagedThreadId) -Option ReadOnly -Force
Set-Variable -Scope Private -Name __lockTaken -Value $false
if ($__inputObject.GetType().IsValueType)
{
$params = @{
Message = "Lock object cannot be a value type."
TargetObject = $__inputObject
Category = [System.Management.Automation.ErrorCategory]::InvalidArgument
ErrorId = 'CannotLockValueType'
}
Write-Error @params
return
}
try
{
Write-Verbose "Thread ${__threadID}: Requesting lock on $__inputObject"
[System.Threading.Monitor]::Enter($__inputObject)
$__lockTaken = $true
Write-Verbose "Thread ${__threadID}: Lock taken on $__inputObject"
. $__scriptBlock
}
catch
{
$params = @{
Exception = $_.Exception
Category = [System.Management.Automation.ErrorCategory]::OperationStopped
ErrorId = 'InvokeWithLockError'
TargetObject = New-Object psobject -Property @{
ScriptBlock = $__scriptBlock
InputObject = $__inputObject
}
}
Write-Error @params
return
}
finally
{
if ($__lockTaken)
{
Write-Verbose "Thread ${__threadID}: Releasing lock on $__inputObject"
[System.Threading.Monitor]::Exit($__inputObject)
Write-Verbose "Thread ${__threadID}: Lock released on $__inputObject"
}
}
}
No comments:
Post a Comment