How to Launch Interactive GUI Applications on Remote Windows Machines Using PowerShell and WinRM


2 views

When working with PowerShell remoting via WinRM, a common frustration emerges: GUI applications launched through Invoke-Command appear to run successfully (confirmed via process listing) but never display visibly on the remote machine's desktop. This behavior stems from fundamental Windows session isolation mechanisms.

Windows maintains strict separation between:

  • Session 0: System services and background processes
  • Session 1+: User interactive sessions

By default, PowerShell remoting creates a non-interactive session (typically Session 1 but without GUI rights), causing launched GUI apps to terminate when the session ends.

Method 1: Scheduled Task Approach

$action = New-ScheduledTaskAction -Execute "calc.exe"
$trigger = New-ScheduledTaskTrigger -AtLogOn
Register-ScheduledTask -TaskName "RemoteGUIApp" -Action $action -Trigger $trigger -Force
Invoke-Command -ComputerName REMOTE-PC -ScriptBlock {
    Start-ScheduledTask -TaskName "RemoteGUIApp"
    Unregister-ScheduledTask -TaskName "RemoteGUIApp" -Confirm:$false
}

Method 2: PSEXEC Alternative

When WinRM isn't mandatory, Sysinternals' PSEXEC can bridge the session gap:

.\PsExec.exe \\REMOTE-PC -i -d calc.exe

The -i flag specifies interactive mode, while -d prevents waiting for process completion.

Method 3: Permanent WinRM Configuration

For frequent GUI remote access, modify the WinRM service:

Invoke-Command -ComputerName REMOTE-PC -ScriptBlock {
    Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" 
    -Name "LocalAccountTokenFilterPolicy" -Value 1 -Type DWord
    Restart-Service WinRM
}

Each solution carries security implications:

  • Scheduled tasks leave temporary artifacts
  • PSEXEC requires SMB ports (often blocked)
  • WinRM configuration changes affect all remote connections

Always evaluate these in your security context before implementation.

For developers needing to launch Visual Studio remotely:

$vsPath = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\devenv.exe"
Invoke-Command -ComputerName DEV-MACHINE -ScriptBlock {
    schtasks /create /tn "VSRemote" /tr "$using:vsPath" /sc once /st 00:00 /ru $env:USERNAME
    schtasks /run /tn "VSRemote"
    Start-Sleep -Seconds 5
    schtasks /delete /tn "VSRemote" /f
}

If applications still don't appear:

  1. Verify the remote user has active desktop sessions
  2. Check Group Policy for "Interactive logon" restrictions
  3. Test with simpler apps (notepad.exe) before complex GUIs

When working with PowerShell remoting via WinRM, you might encounter a peculiar behavior when trying to launch GUI applications. The command executes successfully, but the application window never appears on the remote machine's desktop. This happens because:

  • The process starts in a non-interactive session
  • The GUI has no desktop context to render to
  • The session terminates immediately after execution

Windows implements session isolation for security reasons. When you run Invoke-Command, your remote command executes in session 0 (the non-interactive session), while the user's GUI runs in session 1 or higher.

# This won't show the GUI on remote desktop
Invoke-Command -ComputerName REMOTE-PC -ScriptBlock { 
    Start-Process notepad.exe 
}

Method 1: Using Scheduled Tasks

The most reliable approach is to create a scheduled task that runs in the user's session:

Invoke-Command -ComputerName REMOTE-PC -ScriptBlock {
    $action = New-ScheduledTaskAction -Execute "calc.exe"
    Register-ScheduledTask -TaskName "RemoteGUI" -Action $action -RunLevel Highest
    Start-ScheduledTask -TaskName "RemoteGUI"
    # Optional: Clean up after execution
    Start-Sleep -Seconds 2
    Unregister-ScheduledTask -TaskName "RemoteGUI" -Confirm:$false
}

Method 2: Using psexec with Interactive Flag

If you have Sysinternals tools available, psexec can solve this:

psexec \\REMOTE-PC -i -d calc.exe

Method 3: Remote Desktop Session Execution

For persistent access, you can use RDP and run commands directly:

# First establish RDP connection
mstsc /v:REMOTE-PC

# Then run this locally on the remote machine after logging in
Start-Process "C:\Path\To\YourApp.exe"
  • Always use encrypted WinRM connections (HTTPS)
  • Configure proper firewall rules
  • Use constrained endpoints when possible
  • Consider using Just Enough Administration (JEA)

If you're still having issues:

# Check if WinRM is properly configured
Test-WSMan -ComputerName REMOTE-PC

# Verify firewall rules
Invoke-Command -ComputerName REMOTE-PC -ScriptBlock {
    Get-NetFirewallRule | Where-Object { $_.DisplayName -like "*WinRM*" }
}

# Check session details
query session /server:REMOTE-PC