如何通过PowerShell在远程机器上以编程方式启动可见的桌面应用程序
如何通过PowerShell在远程机器上以编程方式启动可见的桌面应用程序
你遇到的问题我之前也踩过好几次坑——用WMI或者常规Invoke-Command启动的程序明明在进程列表里躺着,就是看不到窗口,这全是Session 0搞的鬼!
为什么之前的方法看不到窗口?
Windows的Session 0是专门给服务和后台进程设计的隔离会话,它完全不绑定任何用户的交互式桌面。你用Win32_Process.Create或者普通Invoke-Command启动程序时,默认就跑在这个会话里,所以进程存在但窗口根本没地方显示。要让程序可见,必须在用户的交互式会话(通常是Session 1及以上,只有用户登录桌面后才会创建)里启动它。
解决方法1:通过WMI指定用户会话启动程序
首先得找到远程机器上当前登录用户的交互式会话ID,然后在启动进程时明确指定这个会话:
# 替换成你的远程机器名称 $remoteComputer = "REMOTE_MACHINE_NAME" # 1. 获取远程机器上的活跃交互式用户会话(LogonType=2表示交互式登录,即用户已登录桌面) $activeLogonSession = Get-WmiObject -ComputerName $remoteComputer -Class Win32_LogonSession -Filter "LogonType=2" | Select-Object -First 1 if (-not $activeLogonSession) { Write-Error "远程机器上没有用户登录到交互式桌面,请先让用户登录后再操作!" exit } # 2. (可选)关联会话到具体用户,用来确认目标会话归属 $loggedOnUser = Get-WmiObject -ComputerName $remoteComputer -Query @" ASSOCIATORS OF {Win32_LogonSession.LogonId='$($activeLogonSession.LogonId)'} WHERE AssocClass=Win32_LoggedOnUser Role=Dependent "@ | Select-Object -ExpandProperty Name Write-Host "将在远程机器的会话 $($activeLogonSession.SessionId)(用户:$loggedOnUser)中启动记事本" # 3. 创建进程启动信息,指定要使用的会话ID $startupInfo = New-Object System.Management.ManagementClass("\\$remoteComputer\root\cimv2:Win32_ProcessStartup") $startupInfo.Properties["SessionId"].Value = $activeLogonSession.SessionId # 4. 通过WMI启动程序 $wmiProcess = [WMIClass]"\\$remoteComputer\root\cimv2:Win32_Process" $result = $wmiProcess.Create("notepad.exe", $null, $startupInfo) if ($result.ReturnValue -eq 0) { Write-Host "记事本已成功在远程桌面显示!" } else { Write-Error "启动失败,错误代码:$($result.ReturnValue)(可以查Win32_Process.Create的错误码对照表排查)" }
解决方法2:用Invoke-Command结合计划任务启动
如果更习惯用Invoke-Command的方式,也可以通过创建临时计划任务的方式,强制在用户的交互式会话中启动程序:
Invoke-Command -ComputerName "REMOTE_MACHINE" -Credential $cred -ScriptBlock { # 获取当前活跃的交互式会话ID(Console对应本地登录,RDP-Tcp对应远程桌面登录) $activeSessionId = quser | Where-Object { $_ -match "Console" -or $_ -match "RDP-Tcp" } | ForEach-Object { ($_ -split '\s+')[2] } | Select-Object -First 1 if (-not $activeSessionId) { Write-Error "未找到活跃的用户桌面会话,请确保用户已登录远程机器的桌面!" return } # 创建临时计划任务,指定在目标会话启动记事本 $taskName = "Temp_StartNotepad_$(Get-Random)" schtasks /create /tn $taskName /tr "notepad.exe" /sc once /st 00:00 /ru "NT AUTHORITY\SYSTEM" /sd 01/01/2000 /f /v1 /session $activeSessionId # 立即触发任务 schtasks /run /tn $taskName # 延迟2秒确保程序启动完成,再删除临时任务 Start-Sleep -Seconds 2 schtasks /delete /tn $taskName /f }
重要注意事项
- 必须有活跃用户会话:如果远程机器上没有用户登录到桌面(不管是本地还是RDP),你根本没法启动可见的桌面程序——因为没有桌面载体可以显示窗口。
- 权限要求:你需要拥有远程机器的管理员权限,不管是WMI操作还是创建计划任务,都需要管理员级别的权限才能执行。
- 版本兼容建议:如果用的是PowerShell 5.1及以上版本,推荐用
Get-CimInstance代替Get-WmiObject(语法几乎一致,CIM是WMI的现代替代方案,稳定性更好)。
按上面的方法操作,不用PsExec也能在远程桌面看到启动的程序窗口了!




