powershell 如何通过进程名称将焦点带到窗口?

r1zhe5dt  于 2023-04-12  发布在  Shell
关注(0)|答案(4)|浏览(151)

如果我理解正确的话,这段代码应该捕获活动窗口并使其保持焦点。concent.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: $_"            
 }

我也试过

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);
 }
bpsygsoo

bpsygsoo1#

我找到了:

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)
}
3pvhb19x

3pvhb19x2#

你有没有想过使用窗口名称?我发现这段代码工作得很好,不会占用很多空间:

$wshell = New-Object -ComObject wscript.shell
$wshell.AppActivate('New Tab - Google Chrome')

此外,如果您需要只按Alt-Tab键返回到最后运行的内容(即:你需要焦点来返回到脚本窗口后,发射的东西关闭)试试这个:

$wshell = New-Object -ComObject wscript.shell
$wshell.SendKeys('%{TAB}')
tpxzln5u

tpxzln5u3#

注意事项:
·这个答案部分使用了与现有答案相同的技术,但也引入了一种新技术,旨在以集中的方式对比这些方法。
·只有下面的最后一个解决方案--需要通过Add-Member按需编译C#代码--在窗口恰好被“最小化”时才能正确激活窗口。
·所有解决方案都使用PSv 4+语法。

重要
除非您的代码在 * 当前前台窗口*中运行,否则Windows * 默认情况下会阻止 * 其他进程窗口 * 的编程激活**:而不是 * 激活 * 目标窗口,其 * 任务栏图标 Flink *。
*启用 * 无条件 * 编程激活需要额外的工作,通过每个会话的P/Invoke调用-参见this answer

基于**WScript.Shell COM对象的.AppActivate()方法**(Inventologist's answer对此进行了提示),可能有一个更简单的解决方案,不需要Add-Type和WinAPI P/Invoke签名

备注

  • 如果目标窗口碰巧被最小化了,这个解决方案会把焦点放在它上面,但不会恢复它。
function Show-Window {
  param(
    [Parameter(Mandatory)]
    [string] $ProcessName
  )

  # As a courtesy, strip '.exe' from the name, if present.
  $ProcessName = $ProcessName -replace '\.exe$'

  # Get the ID of the first instance of a process with the given name
  # that has a non-empty window title.
  # NOTE: If multiple instances have visible windows, it is undefined
  #       which one is returned.
  $procId = (Get-Process -ErrorAction Ignore $ProcessName).Where({ $_.MainWindowTitle }, 'First').Id

  if (-not $procId) { Throw "No $ProcessName process with a non-empty window title found." }

  # Note: 
  #  * This can still fail, because the window could have been closed since
  #    the title was obtained.
  #  * If the target window is currently minimized, it gets the *focus*, but is
  #    *not restored*.
  #  * The return value is $true only if the window still existed and was *not
  #    minimized*; this means that returning $false can mean EITHER that the
  #    window doesn't exist OR that it just happened to be minimized.
  $null = (New-Object -ComObject WScript.Shell).AppActivate($procId)

}

# Sample invocation
Show-Window notepad

如果目标窗口恰好最小化,也可以恢复目标窗口的解决方案需要**Add-Type和WinAPI P/Invoke声明**:
备注

  • 在PowerShell会话中第一次调用该函数时,由于必须编译提供WinAPI访问的helper类型,因此会出现明显的延迟。
  • 与上面的解决方案不同,此解决方案 * 恢复 * 当前最小化的窗口以确保其内容可见,同时正确激活当前最大化的窗口而不恢复它。
function Show-Window {
  param(
    [Parameter(Mandatory)]
    [string] $ProcessName
  )

  # As a courtesy, strip '.exe' from the name, if present.
  $ProcessName = $ProcessName -replace '\.exe$'

  # Get the PID of the first instance of a process with the given name
  # that has a non-empty window title.
  # NOTE: If multiple instances have visible windows, it is undefined
  #       which one is returned.
  $hWnd = (Get-Process -ErrorAction Ignore $ProcessName).Where({ $_.MainWindowTitle }, 'First').MainWindowHandle

  if (-not $hWnd) { Throw "No $ProcessName process with a non-empty window title found." }

  $type = Add-Type -PassThru -NameSpace Util -Name SetFgWin -MemberDefinition @'
    [DllImport("user32.dll", SetLastError=true)]
    public static extern bool SetForegroundWindow(IntPtr hWnd);
    [DllImport("user32.dll", SetLastError=true)]
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);    
    [DllImport("user32.dll", SetLastError=true)]
    public static extern bool IsIconic(IntPtr hWnd);    // Is the window minimized?
'@ 

  # Note: 
  #  * This can still fail, because the window could have been closed since
  #    the title was obtained.
  #  * If the target window is currently minimized, it gets the *focus*, but its
  #    *not restored*.
  $null = $type::SetForegroundWindow($hWnd)
  # If the window is minimized, restore it.
  # Note: We don't call ShowWindow() *unconditionally*, because doing so would
  #       restore a currently *maximized* window instead of activating it in its current state.
  if ($type::IsIconic($hwnd)) {
    $type::ShowWindow($hwnd, 9) # SW_RESTORE
  }

}

# Sample invocation
Show-Window notepad
smtd7mpg

smtd7mpg4#

我用这个脚本来做这个。根据你的需要修改...
例如,默认变量$ProcessNameRegEx$WindowTitleRegEx将移动新的记事本窗口(只需启动其中的几个窗口,而无需指定文件)。
您可以将不同的正则表达式传递给脚本。根据您的需要进行编辑。

Show-WindowByName

#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
}

相关问题