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

时间:2017-03-02 21:58:07

标签: powershell

如果我正确理解了这一点,那么这段代码应该捕获活动窗口并保持焦点。 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: $_"            
 }

我也试过

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

4 个答案:

答案 0 :(得分:3)

我使用此脚本执行此操作。根据需要进行修改......

例如,默认变量$ProcessNameRegEx$WindowTitleRegEx将移动新的记事本窗口(只需启动其中几个而不指定文件)。

您可以将不同的正则表达式传递给脚本。根据您的需求进行编辑。

显示-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
}

答案 1 :(得分:3)

我找到了它:

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

答案 2 :(得分:2)

您是否考虑过使用窗口名称? 我发现这段代码可以很好地工作并且不会占用很多空间:

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

此外,如果您只需要Alt-TAB回到最后运行的内容(即:您需要集中精力在触发某些操作后返回脚本窗口),请尝试以下操作:

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

答案 3 :(得分:0)

注意:
*此答案部分使用与现有答案相同的技术,但还引入了一种新技术,旨在针对性地对比这些方法,尤其是在PowerShell Core 。
*只有下面的 last 解决方案-需要通过Add-Member按需编译C#代码-如果恰好是 minimized ,则会正确激活窗口。
*所有解决方案均使用PSv4 +语法;除非明确指出,否则它们都可以在Windows PowerShell和PowerShell Core(在Windows上)中使用。


基于 Add-Type COM对象的WScript.Shell,可以使用不需要.AppActivate()且带有WinAPI P /调用签名的更简单的解决方案方法Inventologist's answer提示):

注意

  • 如果在打开的窗口中窗口标题不是唯一的,则可能激活了错误的窗口;请参阅以下有关通过PID(进程ID)激活的解决方案

  • 如果目标窗口恰好是 minimized ,则此解决方案会将 focus 置于其上,但不会还原 >。

function Show-Window {
  param(
    [Parameter(Mandatory)]
    [string] $ProcessName
  )

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

  # Get the title 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.
  $winTitle = (Get-Process -ErrorAction Ignore $ProcessName).Where({ $_.MainWindowTitle }, 'First').MainWindowTitle

  if (-not $winTitle) { 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($winTitle)

}

# Sample invocation
Show-Window notepad

一种更可靠的方法是通过PID(进程ID)激活。

以下解决方案使用[Microsoft.VisualBasic.Interaction]类型的静态.AppActivate()方法,该方法也接受PID。

注意

  • 此解决方案仅适用于 Windows PowerShell ,不适用于PowerShell Core

  • 如果目标窗口恰好是 minimized ,则此解决方案会将 focus 置于其上,但不会还原 >。

function Show-Window {
  param(
    [Parameter(Mandatory)]
    [string] $ProcessName
  )

  if ($PSVersionTable.PSVersion.Major -le 5) { Throw "This function is only supported in PowerShell Core." }

  # 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.
  $targetPid = (Get-Process -ErrorAction Ignore $ProcessName).Where({ $_.MainWindowTitle }, 'First').Id

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

  # Load the required assembly.
  Add-Type -ErrorAction Stop -AssemblyName Microsoft.VisualBasic

  # 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*.
  [Microsoft.VisualBasic.Interaction]::AppActivate($targetPid)

}

# Sample invocation
Show-Window notepad

还可以在PowerShell Core (在Windows上)中使用的 PID激活(进程ID)解决方案,确实需要 Add-Type和WinAPI P / Invoke声明

注意

  • 在PowerShell会话中首次调用该功能时,由于必须编译提供WinAPI访问权限的帮助程序类型,因此会出现明显的延迟。

  • 与上述解决方案不同,此解决方案还原当前最小化的窗口以确保其内容可见,同时正确激活当前最大化的窗口而不恢复它。

    < / li>
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 bee 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