You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Start-Process后重新聚焦PowerShell脚本窗口?

问题:启动外部进程后恢复PowerShell脚本窗口焦点

我有一个带菜单的PowerShell脚本,用于日常执行各类操作。其中一项操作通过Start-Process启动进程,但启动后新进程窗口会获得焦点,我希望脚本窗口能重新获得焦点。

  • 不想使用PassThru、NoNewWindow参数(避免进程在脚本内启动)
  • 不想用Minimized/Hidden窗口样式(仍需可见新进程窗口)
  • 尝试调用user32.dll的SetForegroundWindow方法,脚本以管理员运行,但仅能让脚本窗口在任务栏闪烁,无法聚焦
  • 脚本另一部分用VBS的AppActivate可成功聚焦其他窗口并执行按键,但用于脚本自身窗口时无效

尝试过的方法

方法1:调用user32.dll的SetForegroundWindow

Start-Process -FilePath "MyProcessPath"

Start-Sleep -Seconds 1

Add-Type @"
using System;
using System.Runtime.InteropServices;
public class WinAp {
 [DllImport("user32.dll")]
 [return: MarshalAs(UnmanagedType.Bool)]
 public static extern bool SetForegroundWindow(IntPtr hWnd);

 [DllImport("user32.dll")]
 [return: MarshalAs(UnmanagedType.Bool)]
 public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
"@

$p = Get-Process | Where-Object { $_.MainWindowTitle -like "*ScriptTitle*" -and $_.ProcessName -eq "powershell" }

$h = $p.MainWindowHandle
[void] [WinAp]::SetForegroundWindow($h)
[void] [WinAp]::ShowWindow($h, 1)

方法2:VBS的AppActivate(仅对外部窗口有效)

$tempPath = [System.IO.Path]::GetTempFileName().Replace(".tmp", ".vbs")
$code = @'
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.AppActivate "App.exe"
WScript.Sleep 250
WshShell.SendKeys "{ENTER}"
'@

$code | Out-File $tempPath -Encoding ASCII
Start-Process "wscript.exe" $tempPath -Wait
Remove-Item $tempPath

解决方案

方案1:修正user32.dll调用,绕过前台激活限制

Windows对SetForegroundWindow有严格的权限限制,当脚本进程不是当前前台进程的拥有者时,直接调用只会触发任务栏闪烁。可以通过AllowSetForegroundWindow授权后再调用SetForegroundWindow:

Start-Process -FilePath "MyProcessPath"

Start-Sleep -Milliseconds 500 # 可根据实际启动速度调整等待时间

Add-Type @"
using System;
using System.Runtime.InteropServices;
public class WinAp {
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetForegroundWindow(IntPtr hWnd);

    [DllImport("user32.dll")]
    public static extern bool AllowSetForegroundWindow(uint dwProcessId);

    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll")]
    public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
}
"@

# 获取当前前台窗口的进程ID,授权其允许脚本进程设置前台
$foregroundHwnd = [WinAp]::GetForegroundWindow()
[WinAp]::GetWindowThreadProcessId($foregroundHwnd, [ref]$foregroundPid) | Out-Null
[WinAp]::AllowSetForegroundWindow($foregroundPid) | Out-Null

# 定位脚本窗口并激活
$scriptProcess = Get-Process | Where-Object { $_.MainWindowTitle -like "*ScriptTitle*" -and $_.ProcessName -eq "powershell" }
if ($scriptProcess) {
    [WinAp]::AllowSetForegroundWindow($scriptProcess.Id) | Out-Null
    [void][WinAp]::SetForegroundWindow($scriptProcess.MainWindowHandle)
}

方案2:用VBS的AppActivate结合脚本进程ID

之前VBS失效是因为窗口标题匹配不准确,直接使用脚本的进程ID($PID)可以精准定位:

Start-Process -FilePath "MyProcessPath"

Start-Sleep -Milliseconds 500

# 获取当前脚本的进程ID
$scriptPid = $PID

$tempPath = [System.IO.Path]::GetTempFileName().Replace(".tmp", ".vbs")
$code = @"
Set WshShell = WScript.CreateObject("WScript.Shell")
WScript.Sleep 200
WshShell.AppActivate $scriptPid
"@

$code | Out-File $tempPath -Encoding ASCII
Start-Process "wscript.exe" $tempPath -Wait -NoNewWindow
Remove-Item $tempPath

内容的提问来源于stack exchange,提问作者Lusiiky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 08:40:59