PSWindowSwitcherTool.psm1
Add-Type @"
using System; using System.Runtime.InteropServices; using System.Text; public class Win32API { public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); } "@ -ErrorAction Stop function Get-OpenWindows { $windowList = New-Object System.Collections.ArrayList $enumDelegate = [Win32API+EnumWindowsProc]{ param([IntPtr] $hWnd, [IntPtr] $lParam) if (-not [Win32API]::IsWindowVisible($hWnd)) { return $true } $length = [Win32API]::GetWindowTextLength($hWnd) if ($length -eq 0) { return $true } $builder = New-Object System.Text.StringBuilder ($length + 1) [Win32API]::GetWindowText($hWnd, $builder, $builder.Capacity) | Out-Null $title = $builder.ToString() if (![string]::IsNullOrWhiteSpace($title)) { $excludedTitles = @( "Program Manager", "Windows Input Experience" ) if ($excludedTitles -notcontains $title) { $windowList.Add([PSCustomObject]@{ Handle = $hWnd Title = $title }) | Out-Null } } return $true } [Win32API]::EnumWindows($enumDelegate, [IntPtr]::Zero) | Out-Null return $windowList } function Start-PSWindowSwitcherTool { Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $form = New-Object Windows.Forms.Form $form.Text = "Open Windows/Apps" $form.Width = 600 $form.Height = 380 $form.StartPosition = "CenterScreen" $listBox = New-Object Windows.Forms.ListBox $listBox.Width = 560 $listBox.Height = 300 $listBox.Location = New-Object Drawing.Point(10,10) $listBox.Anchor = "Top, Left, Right" $listBox.SelectionMode = "One" $form.Controls.Add($listBox) $cancelButton = New-Object Windows.Forms.Button $cancelButton.Text = "Cancel" $cancelButton.Width = 560 $cancelButton.Height = 30 $cancelButton.Location = New-Object Drawing.Point(10,320) $form.Controls.Add($cancelButton) $windowMap = @{} function Update-WindowList { $openWindows = Get-OpenWindows $currentTitles = @($listBox.Items) | Sort-Object $newTitles = $openWindows.Title | Sort-Object if (-not ($currentTitles -eq $newTitles)) { $listBox.Items.Clear() $windowMap.Clear() foreach ($win in $openWindows) { $listBox.Items.Add($win.Title) | Out-Null $windowMap[$win.Title] = $win.Handle } if ($listBox.Items.Count -eq 0) { $listBox.Items.Add("[No open windows found]") | Out-Null } } } # When the user selects an item, bring that window to front immediately $listBox.Add_SelectedIndexChanged({ $selected = $listBox.SelectedItem if ($selected -and $windowMap.ContainsKey($selected)) { $hWnd = $windowMap[$selected] [Win32API]::ShowWindow($hWnd, 9) | Out-Null # SW_RESTORE [Win32API]::SetForegroundWindow($hWnd) | Out-Null } }) $cancelButton.Add_Click({ $form.Close() }) $timer = New-Object Windows.Forms.Timer $timer.Interval = 2000 $timer.Add_Tick({ Update-WindowList }) $timer.Start() Update-WindowList $form.ShowDialog() } Export-ModuleMember -Function Start-PSWindowSwitcherTool |