6

I made a powershell script that uses GetForegroundWindow() to identify which Window is the currently focused Window. Unfortunately, when the powershell script is executed (via Windows Task Scheduler or a hotkey), the script steals focus of the current foreground app; incorrectly using the Powershell window itself as the Foreground app, instead of the intended foreground app.

I even tried creating an EXE using PS2EXE "-noconsole" setting; however, the script still doesn't doesn't work.

Could someone please suggest a way to execute this script without changing focus of the current foreground Window?

My script code works during tests (ONLY if I add "Start-Sleep -s 5"; and, manually steal back the focus with alt-tab for the script to identify the correct foreground Window.

Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class Tricks {
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
}
"@


function Set-WindowStyle {
param(
    [Parameter()]
    [ValidateSet('FORCEMINIMIZE', 'HIDE', 'MAXIMIZE', 'MINIMIZE', 'RESTORE',
                 'SHOW', 'SHOWDEFAULT', 'SHOWMAXIMIZED', 'SHOWMINIMIZED',
                 'SHOWMINNOACTIVE', 'SHOWNA', 'SHOWNOACTIVATE', 'SHOWNORMAL')]
    $Style = 'SHOW',
    [Parameter()]
    $MainWindowHandle = (Get-Process -Id $pid).MainWindowHandle
)
    $WindowStates = @{
        FORCEMINIMIZE   = 11; HIDE            = 0
        MAXIMIZE        = 3;  MINIMIZE        = 6
        RESTORE         = 9;  SHOW            = 5
        SHOWDEFAULT     = 10; SHOWMAXIMIZED   = 3
        SHOWMINIMIZED   = 2;  SHOWMINNOACTIVE = 7
        SHOWNA          = 8;  SHOWNOACTIVATE  = 4
        SHOWNORMAL      = 1
    }
    Write-Verbose ("Set Window Style {1} on handle {0}" -f $MainWindowHandle, $($WindowStates[$style]))

    $Win32ShowWindowAsync = Add-Type -memberDefinition @"
    [DllImport("user32.dll")]
    public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
"@ -name "Win32ShowWindowAsync" -namespace Win32Functions -passThru

    $Win32ShowWindowAsync::ShowWindowAsync($MainWindowHandle, $WindowStates[$Style]) | Out-Null
}


$a = [tricks]::GetForegroundWindow()

$title = get-process | ? { $_.mainwindowhandle -eq $a }
$title2 = $title | select -ExpandProperty ProcessName

if ($title2 -eq 'Kodi'){

    Set-WindowStyle MINIMIZE $a;
    if (Get-Process -Name Yatse2) {(Get-Process -Name Yatse2).MainWindowHandle | foreach { Set-WindowStyle MINIMIZE $_ }}

} ELSE {

    $title.CloseMainWindow()
}
Matt
  • 45,022
  • 8
  • 78
  • 119
MKANET
  • 573
  • 6
  • 27
  • 51
  • 1
    Looks like you have the tools to do the job. Have you tried finding the powershell window first, since you know it will be in the foreground, and set it to not be active before continuing? `Set-WindowStyle SHOWMINNOACTIVE $PSWindow` – Jan Chrbolka Apr 08 '15 at 01:26
  • Maybe by first minimizing the powershell window, by looking up its MainWindowHandle: $handl = (get-process powershell).MainWindowHandle – Rahvin47 Jan 05 '16 at 13:59

3 Answers3

2

I know this question is old, but I've spent quite some time trying to figure out how to not lose focus from the current window for myself and found some information, so hopefully this will help future readers.

The easiest solution is just to literally simulate an Alt+Tab keypress from within your Powershell script instead of having to do it yourself. The following code comes from this StackOverflow answer:

[void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
[System.Windows.Forms.SendKeys]::SendWait("%{TAB}")
# Retrieve the window handles...

...where % represents the Alt modifier and {TAB} is interpreted as the tab key.

homersimpson
  • 4,124
  • 4
  • 29
  • 39
1

User homersimpson's answer works, but using reflection is a bit slow. You can speed things up by adding the Windows.Forms assembly directly...

Add-Type -AssemblyName System.Windows.Forms

...other imports

#Return focus to the original window.
[System.Windows.Forms.SendKeys]::SendWait("%{TAB}")

...Your Code Here

Again, the % represents Alt and you know what TAB is. You are effectively Alt-Tabbing the new window away, returning focus to your desired one.

Shadesz
  • 33
  • 4
-1
  1. Create task that can be run on demand in Task Scheduler and executes your powershell script
  2. Make sure it is set to be run whether user is logged on or not
  3. Create a shortcut that starts the task

That allows your script to be run without visible window

Harms
  • 69
  • 4