Skip to main content

PowerShell : Getting started with MutEx

After setting up the context for the use case of the MutEx in previous post, it is time to do our homework on the topic.


Theory


MutEx as per the MSDN documentation is:
"A synchronization primitive that grants exclusive access to the shared resource to only one thread. If a thread acquires a mutex, the second thread that wants to acquire that mutex is suspended until the first thread releases the mutex."


Now there are two types of MutEx in .NET world:
  • Local mutexes (which are unnamed), can only be used by any thread in our process that has reference to the Mutex Object.
  • Named system mutexes, visible throughout the Operating system and hence can be used as an interprocess synchronization mechanism. Now on a sever which is running Terminal services and hence multiple terminal sessions, the named system mutex can have two levels of visibility.
    • If the mutex name begins with prefix "Local\", it is only visible in the Terminal session where it was created. (Default one, if no prefix specified).
    • If the mutex name begins with prefix "Global\", it is visible in all the Terminal sessions running on the server.


Practical


So we have cleared the theoretical aspects out, now let's take a look at how to create a MutEx (Named Local mutex) object and see it in action. Below are the step :
  1. First step is to create the Mutex Object using the constructor here. Note that the default visibility for the Named mutex is 'Local'.


    $createdNew = $False # Stores Boolean value if the current PowerShell Process gets a lock on the Mutex
    # Create the Mutex Object usin the constructuor -> Mutex Constructor (Boolean, String, Boolean)
    $mutex = New-Object -TypeName System.Threading.Mutex($true, "MutexName1", [ref]$createdNew)

  2. Now the variable $createdNew will have $True if the current PowerShell process ,where you ran this code got a lock on the MutEx object. You can open another PowerShell instance and verify that the only the first process has $CreateNew set to True




    $mutex will contain the MutEx object in it.
  3. So in your project which spans across multiple PowerShell scripts, the very first step will be try to acquire the lock during the creation of the Mutex Object. If you get the lock on the MutEx then very well, go ahead and use the shared resource say a config file. But if you don't get the lock on the MutEx then you have to call the WaitOne() method on the MutEx object.

    There are multiple method overloads but we can simply use the WaitOne() method, which blocks the current PowerShell process until it receives the lock.

    See below, if I release the MutEx from the first process the second one gets the lock post it.


  4. Now, In your code once you have the MutEx lock , you can go ahead and use the shared resource. But remember to release the MutEx by calling the ReleaseMutex() method.

    If you don't  release the mutex in your code (say your function) then when some other process tries to get a lock on the MutEx an AbandonedMutexException is thrown.


Note - If you plan to use MutEx in your code then PowerShell should be running in Single Threaded ApartmentState (STA). Explained by MVP Oisin here.
PowerShell v3 onwards both the Console and ISE by default run in STA mode.

Summary


Now since we have the basics of working with a MutEx explained. Now it is time to summarize how the Invoke-ActionWithMutex & Get-AzureStackDeploymentStatus function work. (See this post if you don't know where this is coming from).

The Get-AzureStackDeploymentStatus function is straight enough, it calls for reading the XML file 'C:\ProgramData\Microsoft\AzureStackAzureStackDeploymentStatus.xml'. See below:


function Get-AzureStackDeploymentStatus
{
    [CmdletBinding()]
    param()
    if (-not (Test-Path $statusFilePath)) {
        Update-AzureStackDeploymentStatus $StatusTemplate | Out-Null
    }

    Invoke-ActionWithMutex -Action {
        [xml](Get-Content $statusFilePath)
    }
}

I have tried explaining how the Invoke-ActionWithMutex function works in below screenshot, it should be straight enough to understand.



Note - To invoke the Scriptblock in Line 24 , Invoke-Command is used to ensure that the ApartmentState for the runspace is STA.

I see MutEx as a powerful technique that can be used in our deployment workflows, I intend to do few more posts after I have explored them a bit more. Meanwhile take a look at some very good posts in the below section :)

Resources :


MutEx Class - Read up the MSDN documentation to grasp the details of this.
https://msdn.microsoft.com/en-us/library/system.threading.mutex%28v=vs.110%29.aspx

Excellent post by MVP Boe Prox on using MutEx to write data to same log file (uses runspaces with MutEx too).
http://learn-powershell.net/2014/09/30/using-mutexes-to-write-data-to-the-same-logfile-across-processes-with-powershell/

Lee Holmes post on enforcing single user access to custom PSRemoting endpoint using MutEx.
http://www.leeholmes.com/blog/2011/08/24/enforcing-single-user-access-to-powershell-remoting/

Popular posts from this blog

Test connectivity via a specific network interface

Recently while working on a Private cloud implementation, I came across a scenario where I needed to test connectivity of a node to the AD/DNS via multiple network adapters.  Many of us would know that having multiple network routes is usually done to take care of redundancy. So that if a network adapter goes down, one can use the other network interface to reach out to the node. In order to make it easy for everyone to follow along, below is an analogy for the above scenario: My laptop has multiple network adapters (say Wi-Fi and Ethernet) connected to the same network. Now how do I test connectivity to a Server on the network only over say Wi-Fi network adapter?

PowerShell + SCCM : Run CM cmdlets remotely

Today I saw a tweet about using implicit remoting to load the Configuration Manager on my machine by Justin Mathews . It caught my eye as I have never really tried it, but theoretically it can be done. Note - The second tweet says "Cannot find a provider with the name CMSite", resolution to which is in the Troubleshooting section at the end.

PowerShell : Trust network share to load modules & ps1

Problem Do you have a central network share, where you store all the scripts or PowerShell modules ? What happens if you try to run the script from a network share ? or if you have scripts (local) which invoke scripts or import PowerShell modules stored on this network share ? Well you would see a security warning like below (Note - I have set execution policy as 'Unrestricted' not 'bypass' here): Run a .ps1 from the network share Well this is a similar warning, which you get when you download scripts from Internet. As the message says run Unblock-File cmdlet to unblock the script and then run it, let's try it.