如何通过PowerShell远程检测窗口是否打开及处理后台挂起的Acrobat进程
Got it, let's break down why your remote PowerShell approach isn't working and walk through some solid fixes.
First, the root issue: Your local script works because it runs in your interactive desktop session—meaning it can access user32.dll APIs, enumerate open windows, and check process window states without restrictions. But PowerShell remote sessions default to running in a non-interactive background session (Session 0), which has no access to the user's desktop context. That's why your window-detection logic fails remotely.
Here are three actionable solutions tailored to this problem:
Solution 1: Run your detection script in the target user's interactive session
This is the most reliable fix because it lets you reuse your already-working local logic. You just need to launch the script directly in the user's desktop session instead of the remote background session:
- First, get the interactive session ID for the logged-in user on the remote machine:
$sessionId = (Get-CimInstance Win32_LogonSession | Where-Object { $_.LogonType -eq 2 }).SessionId # LogonType 2 = interactive user session (local or RDP) - Use
Invoke-Commandto start your cleanup script in that specific session:
This ensures your script runs in the user's desktop context, so all your window-detection logic works exactly like it does locally.Invoke-Command -ComputerName <RemotePCName> -ScriptBlock { param($sessionId) # Assume your working local script is saved as Cleanup-Acrobat.ps1 on the remote machine $scriptPath = "C:\Temp\Cleanup-Acrobat.ps1" Start-Process powershell.exe -ArgumentList "-File `"$scriptPath`"" -SessionId $sessionId -WindowStyle Hidden } -ArgumentList $sessionId
Solution 2: Detect hung Acrobat via process attributes (no window checks needed)
If you don't want to mess with session IDs, you can identify hung Acrobat processes using their resource or command-line properties instead:
- Check for processes with no open PDF files: Use WMI to inspect open file handles, or filter by command line (if no PDF path is present, it's likely a hung background process).
- Check for idle resource usage: Hung Acrobat processes typically sit at 0% CPU and have low, stable memory usage.
Example script for this approach:
Invoke-Command -ComputerName <RemotePCName> -ScriptBlock { Get-Process -Name AcroRd32, Acrobat | Where-Object { # Filter out processes with no window title (remote sessions might blank this for visible windows, so combine with other checks) [string]::IsNullOrEmpty($_.MainWindowTitle) -and # Filter out processes that aren't opening a PDF file $_.CommandLine -notmatch "\.pdf$" -and # Filter out processes using minimal CPU over time (adjust threshold as needed) $_.CPU -lt 1 } | Stop-Process -Force }
Note: Tweak the conditions to match your environment—this might accidentally close Acrobat if a user has it open without a PDF, so test thoroughly.
Solution 3: Embed C# window-enumeration logic (run in interactive session)
If you want to stick to window detection but need a remote-compatible way, embed C# code that calls user32.dll APIs to find processes with visible windows. Just remember to run this in the user's interactive session (like Solution 1):
Invoke-Command -ComputerName <RemotePCName> -ScriptBlock { Add-Type @" using System; using System.Runtime.InteropServices; using System.Collections.Generic; public class WindowChecker { public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); [DllImport("user32.dll")] public static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam); [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr hWnd); public static List<uint> GetVisibleProcessIds() { List<uint> pids = new List<uint>(); EnumWindows((hWnd, lParam) => { if (IsWindowVisible(hWnd)) { uint pid; GetWindowThreadProcessId(hWnd, out pid); if (!pids.Contains(pid)) pids.Add(pid); } return true; }, IntPtr.Zero); return pids; } } "@ $visibleProcessIds = [WindowChecker]::GetVisibleProcessIds() # Stop Acrobat processes that don't have any visible windows Get-Process -Name AcroRd32, Acrobat | Where-Object { $visibleProcessIds -notcontains $_.Id } | Stop-Process -Force }
Content adapted from a question on stack exchange, asked by Ryan

