PowerShell – Using psexec to automate UI tasks on remote machines

When you use PowerShell native remoting commands, e.g. invoke-command, the remote server acts as a terminal server, and doesn't have an active UI session. This means that you can't do something like this:

powershell -computername {name} -scriptblock {notepad.exe}

Officially there are no powershell cmdlets that you can use to remotely control the gui.

Instead you have to use another microsoft owned utility called "psexec". This is a standalone exe that you can download for free. However psexec comes as part of a bundle of other exe. This bundle is called pstools.

So all you need to do is

  1. download pstools (which is a zip file),
  2. unblock it (right click on the zip file | properties | unblock button) if necessary,
  3. then just extract the psexec.exe
  4. Place the file in a memorable place, preferably in the one of the following directories: $env:path.split(";")


Now from the cmd or powershell, you can do:

& psexec.exe \\{machine-name} -u {domain}\{username} -p {username} -w c:\temp -d -h -i 2 notepad.exe

Note: the ampersand is a way to tell powershell to pass the rest of the line to cmd. However I think you can leave out the ampersand and will still work in Powershell.

One of the first things you may need to do is:

psexec.exe \\$servername -u os\$username -p $password -w c:\temp -d -h powershell.exe "Enable-PSRemoting -Force"

You can run the above from within a powershell terminal and don't even need to start the command with an ampersand. Also the variables are automatically first evaluated before psexec.exe takes over 🙂

You can find the remote session id here:

qwinsta /SERVER:{server-name}

This outputs a table in the form of a really long string, which is tricky to deal with, but you can retrieve the session id, using:

$DirtyQwinstaArray = (qwinsta /SERVER:{machine-name}| Where-Object -FilterScript {$_ -match "{username}"}) -split (" ")
# "DirtyQwinstaArray" contains array items that are just whitespace, these needs to be cleaned up.

$CleanQwinstaArray = @()
$DirtyQwinstaArray | ForEach-Object {

if ($_ -eq $DirtyQwinstaArray[2]){
# "null found"
else {
$CleanQwinstaArray += $_

$RDPsessionID = $CleanQwinstaArray[2]

However if you don't have an active session, then I think you can set one via a powershell script using "cmdkey" and "mstsc":

usefule links:

A fun script for Friday - make your friend's computer start talking to him/her from PowerShell