如果我正确理解了此代码,则该代码应捕获活动窗口并保持其焦点。concentr.exe是进程名称。如何根据进程名称使窗口聚焦?
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class UserWindows {
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
"@
try {
$ActiveHandle = [UserWindows]::GetForegroundWindow()
$Process = Get-Process | ? {$_.MainWindowHandle -eq $activeHandle}
$Process | Select ProcessName, @{Name="concentr.exe";Expression= {($_.MainWindowTitle)}}
} catch {
Write-Error "Failed to get active Window details. More Info: $_"
}
Run Code Online (Sandbox Code Playgroud)
我也尝试过
param([string] $proc="Citrix Connection Manager", [string]$adm)
cls
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 {$_.mainWindowTItle }|where {$_.Name -like "$proc"}
if (($p -eq $null) -and ($adm -ne ""))
{
Start-Process "$proc" -Verb runAs
}
elseif (($p -eq $null) -and ($adm -eq ""))
{
Start-Process "$proc" #-Verb runAs
}
else
{
$h = $p.MainWindowHandle
[void] [WinAp]::SetForegroundWindow($h)
[void] [WinAp]::ShowWindow($h,3);
}
Run Code Online (Sandbox Code Playgroud)
mkl*_*nt0 14
注意:
\n\xe2\x80\xa2 这个答案部分使用了与现有答案相同的技术,但也引入了一种新技术,旨在集中对比这些方法。
\n\xe2\x80\xa2 只有下面的最后一个解决方案 - 需要通过按需编译 C# 代码Add-Member- 如果窗口恰好被最小化,则可以正确激活窗口。
\n\xe2\x80\xa2 所有解决方案均使用 PSv4+ 语法。
重要的:
\n除非您的代码在当前前台窗口中运行,否则Windows默认情况下会阻止以编程方式激活其他进程的窗口:其任务栏图标会闪烁,而不是激活目标窗口。
\n启用无条件编程激活需要额外的工作,通过每个会话 P/Invoke 调用 - 请参阅此答案。
\n基于COM 对象的方法(发明家的回答) ,可以有一个不需要Add-TypeWinAPI P/Invoke 签名的更简单的解决方案WScript.Shell.AppActivate()暗示)
笔记:
\n如果目标窗口恰好被最小化,此解决方案确实会将焦点放在它上面,但不会恢复它。
\n解决方案的要点如下,Notepad以进程名称为例;该语句激活具有非空窗口标题的该名称的(第一个)进程(如果您可以假设目标进程始终具有窗口标题,因此可以假定为可见,您可以简化为(Get-Process Notepad)[0].Id):
$null = (New-Object -ComObject WScript.Shell).AppActivate(\n (Get-Process Notepad).Where({ $_.MainWindowTitle }, \'First\').Id\n)\nRun Code Online (Sandbox Code Playgroud)\nfunction Show-Window {\n param(\n [Parameter(Mandatory)]\n [string] $ProcessName\n )\n\n # As a courtesy, strip \'.exe\' from the name, if present.\n $ProcessName = $ProcessName -replace \'\\.exe$\'\n\n # Get the ID of the first instance of a process with the given name\n # that has a non-empty window title.\n # NOTE: If multiple instances have visible windows, it is undefined\n # which one is returned.\n $procId = (Get-Process -ErrorAction Ignore $ProcessName).Where({ $_.MainWindowTitle }, \'First\').Id\n\n if (-not $procId) { Throw "No $ProcessName process with a non-empty window title found." }\n\n # Note: \n # * This can still fail, because the window could have been closed since\n # the title was obtained.\n # * If the target window is currently minimized, it gets the *focus*, but is\n # *not restored*.\n # * The return value is $true only if the window still existed and was *not\n # minimized*; this means that returning $false can mean EITHER that the\n # window doesn\'t exist OR that it just happened to be minimized.\n $null = (New-Object -ComObject WScript.Shell).AppActivate($procId)\n\n}\n\n# Sample invocation\nShow-Window notepad\nRun Code Online (Sandbox Code Playgroud)\n如果目标窗口恰好最小化,也可以恢复目标窗口的解决方案需要Add-Type使用 WinAPI P/Invoke 声明:
笔记:
\n在 PowerShell 会话中首次调用该函数时,由于必须编译提供 WinAPI 访问的帮助程序类型,因此存在明显的延迟。
\n与上面的解决方案不同,该解决方案恢复当前最小化的窗口以确保其内容可见,同时正确激活当前最大化的窗口而不恢复它。
\nfunction Show-Window {\n param(\n [Parameter(Mandatory)]\n [string] $ProcessName\n )\n\n # As a courtesy, strip \'.exe\' from the name, if present.\n $ProcessName = $ProcessName -replace \'\\.exe$\'\n\n # Get the PID of the first instance of a process with the given name\n # that has a non-empty window title.\n # NOTE: If multiple instances have visible windows, it is undefined\n # which one is returned.\n $hWnd = (Get-Process -ErrorAction Ignore $ProcessName).Where({ $_.MainWindowTitle }, \'First\').MainWindowHandle\n\n if (-not $hWnd) { Throw "No $ProcessName process with a non-empty window title found." }\n\n $type = Add-Type -PassThru -NameSpace Util -Name SetFgWin -MemberDefinition @\'\n [DllImport("user32.dll", SetLastError=true)]\n public static extern bool SetForegroundWindow(IntPtr hWnd);\n [DllImport("user32.dll", SetLastError=true)]\n public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); \n [DllImport("user32.dll", SetLastError=true)]\n public static extern bool IsIconic(IntPtr hWnd); // Is the window minimized?\n\'@ \n\n # Note: \n # * This can still fail, because the window could have been closed since\n # the title was obtained.\n # * If the target window is currently minimized, it gets the *focus*, but its\n # *not restored*.\n $null = $type::SetForegroundWindow($hWnd)\n # If the window is minimized, restore it.\n # Note: We don\'t call ShowWindow() *unconditionally*, because doing so would\n # restore a currently *maximized* window instead of activating it in its current state.\n if ($type::IsIconic($hwnd)) {\n $type::ShowWindow($hwnd, 9) # SW_RESTORE\n }\n\n}\n\n# Sample invocation\nShow-Window notepad\nRun Code Online (Sandbox Code Playgroud)\n
我找到了:
Param(
[string] $proc="C:\Program Files (x86)\Citrix\ICA Client\concentr.exe",
[string] $adm
)
Clear-Host
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 {$_.mainWindowTitle} |
Where {$_.Name -like "$proc"}
if (($p -eq $null) -and ($adm -ne "")) {
Start-Process "$proc" -Verb runAs
} elseif (($p -eq $null) -and ($adm -eq "")) {
Start-Process "$proc"
} else {
$h = $p.MainWindowHandle
[void] [WinAp]::SetForegroundWindow($h)
[void] [WinAp]::ShowWindow($h, 3)
}
Run Code Online (Sandbox Code Playgroud)
你有没有想过使用窗口名称?我发现这段代码很好用,而且不占用太多空间:
$wshell = New-Object -ComObject wscript.shell
$wshell.AppActivate('New Tab - Google Chrome')
Run Code Online (Sandbox Code Playgroud)
此外,如果您只需要按 Alt-TAB 键返回上次运行的内容(即:您需要在关闭某些内容后将焦点返回到脚本窗口),请尝试以下操作:
$wshell = New-Object -ComObject wscript.shell
$wshell.SendKeys('%{TAB}')
Run Code Online (Sandbox Code Playgroud)
我使用这个脚本来做到这一点。根据需要修改...
例如,默认变量$ProcessNameRegEx和$WindowTitleRegEx将移动新的记事本窗口(只需启动其中几个而不指定文件)。
您可以将不同的正则表达式传递给脚本。根据您的需求进行编辑。
按名称显示窗口
#Requires -RunAsAdministrator
[CmdletBinding()]
param (
[string]
$ProcessNameRegEx = 'notepad',
[string]
$WindowTitleRegEx = 'unt'
)
$cs = @"
using System;
using System.Runtime.InteropServices;
namespace User32
{
public static class WindowManagement
{
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
public const int SWP_NOSIZE = 0x01, SWP_NOMOVE = 0x02, SWP_SHOWWINDOW = 0x40, SWP_HIDEWINDOW = 0x80;
public static void SetWindowPosWrappoer(IntPtr handle, int x, int y, int width, int height)
{
if (handle != null)
{
SetWindowPos(handle, 0, x, y, 0, 0, SWP_NOSIZE | SWP_HIDEWINDOW);
if (width > -1 && height > -1)
SetWindowPos(handle, 0, 0, 0, width, height, SWP_NOMOVE);
SetWindowPos(handle, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
}
}
[DllImport("user32.dll", EntryPoint = "ShowWindow")]
public static extern IntPtr ShowWindow(IntPtr hWnd, int nCmdShow);
public static void ShowWindowWrapper(IntPtr handle, int nCmdShow)
{
if (handle != null)
{
ShowWindow(handle, nCmdShow);
}
}
[DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
public static extern IntPtr SetForegroundWindow(IntPtr hWnd);
public static void SetForegroundWindowWrapper(IntPtr handle)
{
if (handle != null)
{
SetForegroundWindow(handle);
}
}
}
}
"@
Add-Type -TypeDefinition $cs -Language CSharp -ErrorAction SilentlyContinue
function Move-Window
{
param (
[int]$MainWindowHandle,
[int]$PosX,
[int]$PosY,
[int]$Height,
[int]$Width
)
if($MainWindowHandle -ne [System.IntPtr]::Zero)
{
[User32.WindowManagement]::SetWindowPosWrappoer($MainWindowHandle, $PosX, $PosY, $Width, $Height);
}
else
{
throw "Couldn't find the MainWindowHandle, aborting (your process should be still alive)"
}
}
function Show-Window
{
param (
[int]$MainWindowHandle,
[int]$CmdShow
)
if($MainWindowHandle -ne [System.IntPtr]::Zero)
{
[User32.WindowManagement]::ShowWindowWrapper($MainWindowHandle, $CmdShow);
[User32.WindowManagement]::SetForegroundWindowWrapper($MainWindowHandle);
}
else
{
throw "Couldn't find the MainWindowHandle, aborting (your process should be still alive)"
}
}
$windows = Get-Process | ? {$_.ProcessName -match $ProcessNameRegEx -and $_.MainWindowTitle -match $WindowTitleRegEx} | Select -Last 100 | Select Id, MainWindowTitle, MainWindowHandle | Sort MainWindowTitle
$h = 180
$w = 1500
$x = 400
$y = 800
$deltax = 80
$deltay = 180
foreach ($window in $windows)
{
Move-Window $window.MainWindowHandle $x $y $h $w
Show-Window $window.MainWindowHandle 5
#$x -= $deltax
$y -= $deltay
}
Run Code Online (Sandbox Code Playgroud)