Search code examples
windowspowershellcmdserverscripting

How do I restart a batch file in PowerShell?


Here is what I have tried:

Get-Process | Where-Object {$_.Path -eq "C:\path\stream1.bat"} | Stop-Process -Force

Start-Sleep -Seconds 5

Start-Process -FilePath "cmd.exe" -ArgumentList "/c `"C:\path\stream1.bat`""

The Start-Process command works perfectly, however the Stop-Process command does nothing.


Solution

  • One issue with your current code is that .Path (in reality this property is .MainModule.FileName) will be the path to cmd.exe not the .bat file itself. What you can do in this case is query Win32_Process and filter by the CommandLine property where it contains the path of your .bat. This solves one of the problems.

    The next problem will be to find all sub processes that your .bat file could've started, these need to be terminated first before terminating cmd.exe itself. For this, again, you can query Win32_Process to find all processes having the ParentProcessId equal to the process id of your cmd.exe process.

    $bat = 'C:\path\stream1.bat'
    
    # WQL requires escaping of `\`
    $cmdline = $bat.Replace('\', '\\')
    
    $getCimInstanceSplat = @{
        Filter    = "Name = 'cmd.exe' AND CommandLine LIKE '%$cmdline%'"
        ClassName = 'Win32_Process'
    }
    # Find the cmd process containing the path of the `.bat` file
    $proc = Get-CimInstance @getCimInstanceSplat
    
    $getCimInstanceSplat = @{
        Filter    = "ParentProcessId = '$($proc.ProcessId)'"
        ClassName = 'Win32_Process'
    }
    # Find all processes started by that bat file
    Get-CimInstance @getCimInstanceSplat |
        # and terminate all of them
        Invoke-CimMethod -MethodName Terminate
    
    # In case the parent process didn't terminate after that
    # attempt to terminate it as well
    $proc | Invoke-CimMethod -MethodName Terminate -EA 0