Tuesday, January 22, 2013

Ensuring that two PowerShell scripts don't run at the same time

This quick PowerShell snippet shows how you can ensure only one instance of a script or section of a script executes at a time on a system, i.e. a server running scheduled tasks.

The script will wait while the other script or section completes. The Dispose method releases the mutex and allows any other scripts to take it and run. It should ideally be in a finally block to ensure it always gets released, although I've read that it uses a .NET critical finalizer to ensure release but I don't know if this works as well in PowerShell as it would in a proper .NET process.

    [System.Threading.Mutex]$mutant;
    try
    {
        # Obtain a system mutex that prevents more than one deployment taking place at the same time.
        [bool]$wasCreated = $false;
        $mutant = New-Object System.Threading.Mutex($true, "MyMutex", [ref] $wasCreated);        
        if (!$wasCreated)
        {            
            $mutant.WaitOne();
        }

        ### Do Work ###
    }
    finally
    {       
        $mutant.ReleaseMutex(); 
        $mutant.Dispose();
    }

7 comments:

  1. Added ReleaseMutex call before dispose, since dispose doesn't seem to release. By design?

    ReplyDelete
  2. When I try to run this, I get "Method invocation failed because [System.Threading.Mutex] doesn't contain a method named 'Dispose'."

    ReplyDelete
  3. I'll be honest Paul, I have no idea why! You could try Close() instead, it does mostly the same thing.

    ReplyDelete
  4. Good call, Luke. $mutant.Close() doesn't give me the error. My guess is something to do with the version of .NET I'm running.

    ReplyDelete
  5. Good stuff. Funny, I can't image a world in which a Mutex was IDisposable. I don't know if you're a .NET guy but any type that creates kernel objects, or other resources that like outside of .NET, must implement IDisposable (i.e. have a Dispose method). In any case, the Close method will release everything. Cheers Paul.

    ReplyDelete
  6. Sheeze, I can't type today. was = wasn't and like = live.

    ReplyDelete
  7. https://powershell.org/forums/topic/powershell-mutex-not-working-as-expected/ This code works, but while trying to implement "single instance, exit on mutex not acquired", Close() seems to be better than Dispose()

    ReplyDelete