Friday, July 20, 2012

Start remote process through WMI

There are many ways to execute a process remotely on a Windows based computer. It is possible use Remote Desktop (RDP/MSTSC) to log onto the desktop of the computer, but this is slow and not easily automated.
You can use the excellent  Sysinternals tools PSEXEC, provided by Microsoft or you can use PowerShell 2.0's support for WinRM.

While all of the options above might be good in any specific situation, I would like to share an alternative : using WMI to initiate a remote process.

The small function below, allows you to initiate a process on a remote computer, and - should you want to - wait for its completion. The function does not allow you to return the result of the process, but it is possible to direct the output to a local file, and access that file afterwards through some other mean.


Function NewProcessWMI {
    Param (
        $target = ".",
        $command = "dir",
        [switch]$WaitForCompletion
    )
    $cmdResult = ([WmiClass]"\\$target\ROOT\CIMV2:Win32_Process").create($command)
    Switch ($cmdresult.returnvalue) {
        0 {$resultTxt = "Successful"}
        2 {$resultTxt = "Access denied"}
        3 {$resultTxt = "Insufficient privilege"}
        8 {$resultTxt = "Unknown failure"}
        9 {$resultTxt = "Path not found"}
        21 {$resultTxt = "Invalid parameter"}
        default {$resultTxt = "Unhandled error"}
    }
    $processId = $cmdresult.processId
    $processStatus = "unknown"
    if ($WaitForCompletion) {
        $wait = $true
        While ($wait) {
            Start-Sleep -Milliseconds 250
            $test = Get-WmiObject -query "select * from Win32_Process Where ProcessId='$processId'"
            if ((Measure-Object -InputObject $test).count -eq 0) {
                $wait = $false
            }
        }
        $processStatus = "completed"
    }
    $obj = New-Object Object
    $obj | Add-Member Noteproperty Target -value $target
    $obj | Add-Member Noteproperty Command -value $command
    $obj | Add-Member Noteproperty Result -value $($cmdresult.returnvalue)
    $obj | Add-Member Noteproperty ProcessStart -value $resultTxt
    $obj | Add-Member Noteproperty ProcessId -value $processId
    $obj | Add-Member Noteproperty ProcessStatus -value $processStatus
    $obj
}

The function can be used as follows:


NewProcessWMI "." "cmd /c ipconfig" -WaitForCompletion | ft -au
NewProcessWMI "." "cmd /c dir c:\users\*.* /s" -WaitForCompletion | ft –au


To direct the output to a file:

NewProcessWMI "." "cmd /c ipconfig > C:\ipconfigResult.txt" -WaitForCompletion | ft -au


You must have some way of reading the C:\ipconfigResults.txt afterwards, as this script (and WMI in general) doesn't provide such capabilities.


2 comments:

Sunny Chakraborty said...

Hi Jakob
Can you target the process launch on any session other than WinSta0 ?

I tested this on a remote computer and it launches on Console Session.

Objective is > If we can target this on anything other than Console session, then it makes a lot of sense in a large scale VDI environment.

Unknown said...

Once you replace negative thoughts with positive ones, you'll start having positive results. See the link below for more info.


#start
www.ufgop.org