Command/Environment/GetLockingProcess.ps1


Import-Module CmxModule -Force -DisableNameChecking

function GetLockingProcessList
{
    <#
    .SYNOPSIS
    Gets the process list which locks the given file.
    #>


    [cmdletbinding()]
    Param
    (
        [Parameter(Position = 0, Mandatory = $true, HelpMessage = "Path to the file to check.")]
        [ValidateNotNullorEmpty()]
        [string]$Path,

        [Parameter(Position = 1, Mandatory = $true, HelpMessage = "Path to the sysinternals [handle.exe].")]
        [ValidateNotNullorEmpty()]
        [string]$HandleExe
    )

    [regex]$expression = 
        "^(?<Name>.+)\s+" +
        "pid:\s+(?<PID>\d+)\s+" +
        "type:\s+(?<Type>\w+)\s+" +
        "(?<User>.+)\s+" +
        "\w+:\s+" +
        "(?<Path>.*)$"
    
    # https://docs.microsoft.com/en-us/sysinternals/downloads/handle
    $lines = & "$HandleExe" -u -a -nobanner "$Path" 
    $lines = $lines | Where-Object { $_.ToString().Length -gt 0 }
    $lines | Foreach-Object {
        $matchList = $expression.Matches($_)
        if($matchList.Count)
        {
            $match = $matchList[0]
            $groups = $match.groups
            [PsCustomObject]@{
                Text = $match.ToString()
                Name = $groups["Name"].Value.Trim()
                ProcessId = $groups["PID"].Value.Trim()
                Type = $groups["Type"].Value.Trim()
                User = $groups["User"].Value.Trim()
                Path = $groups["Path"].Value.Trim()
            }
        }        
    }
}

SetWindowTitle $MyInvocation.MyCommand.Name
Write-Output "Gets the process which locks a file via sysinternals handle tool."
$filePath = Read-Host "Enter the file path"
if(-not $filePath)
{
    $filePath = $BinariesFolder + "\Release\x64"
}
Write-Output "Path: $filePath"
$handleExe = $CmxRootFolder + "\Internals\Handle\handle.exe"
if(-not(Test-Path $handleExe))
{
    Write-Output "The path to the handle tool [$handleExe] does not exist."
    Read-Host "The script has finished. Press any key to exit"
    exit 1
}
Write-Output "Get locking process list . . ."
[array]$processList = GetLockingProcessList -Path $filePath -HandleExe $handleExe
Write-Output "Get locking process list has finished"
if($processList.Count)
{
    Write-Output "Found locking processes"
    $uniquePids = $processList | Foreach-Object { $_.ProcessId } | Get-Unique -AsString
    [array]$processes = Get-Process -PID $uniquePids -ErrorAction Ignore
    $processes | Format-Table ProcessName, Id
    $answer = Read-Host "Do you like to stop the processes (Y|N)"
    if($answer -eq "Y")
    {     
        Stop-Process -InputObject $processes -Force
        $processes = Get-Process -PID $uniquePids -ErrorAction Ignore
        $stillRunningProcesses = $processes | Where-Object { $_.HasExited -eq $false }
        $count = $stillRunningProcesses.Count
        if($count -gt 0)
        {
            Write-Output "Not all instances were stopped."
        }
        else
        {
            Write-Output "Instances were successfully stopped."
        }
    }
}

Read-Host "The script has finished. Press any key to exit"
exit 0