- 
      
 - 
        
Save lalibi/3762289efc5805f8cfcf to your computer and use it in GitHub Desktop.  
| function Set-WindowState { | |
| <# | |
| .SYNOPSIS | |
| Set the state of a window. | |
| .DESCRIPTION | |
| Set the state of a window using the `ShowWindowAsync` function from `user32.dll`. | |
| .PARAMETER InputObject | |
| The process object(s) to set the state of. Can be piped from `Get-Process`. | |
| .PARAMETER State | |
| The state to set the window to. Default is 'SHOW'. | |
| .PARAMETER SuppressErrors | |
| Suppress errors when the main window handle is '0'. | |
| .PARAMETER SetForegroundWindow | |
| Set the window to the foreground | |
| .PARAMETER ThresholdHours | |
| The number of hours to keep the window handle in memory. Default is 24. | |
| .EXAMPLE | |
| Get-Process notepad | Set-WindowState -State HIDE -SuppressErrors | |
| .EXAMPLE | |
| Get-Process notepad | Set-WindowState -State SHOW -SuppressErrors | |
| .LINK | |
| https://gist.github.com/lalibi/3762289efc5805f8cfcf | |
| .NOTES | |
| Original idea from https://gist.github.com/Nora-Ballard/11240204 | |
| #> | |
| [CmdletBinding(DefaultParameterSetName = 'InputObject')] | |
| param( | |
| [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] | |
| [Object[]] $InputObject, | |
| [Parameter(Position = 1)] | |
| [ValidateSet( | |
| 'FORCEMINIMIZE', 'HIDE', 'MAXIMIZE', 'MINIMIZE', 'RESTORE', | |
| 'SHOW', 'SHOWDEFAULT', 'SHOWMAXIMIZED', 'SHOWMINIMIZED', | |
| 'SHOWMINNOACTIVE', 'SHOWNA', 'SHOWNOACTIVATE', 'SHOWNORMAL' | |
| )] | |
| [string] $State = 'SHOW', | |
| [switch] $SuppressErrors = $false, | |
| [switch] $SetForegroundWindow = $false, | |
| [int] $ThresholdHours = 24 | |
| ) | |
| Begin { | |
| $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 | |
| } | |
| $Win32ShowWindowAsync = Add-Type -MemberDefinition @' | |
| [DllImport("user32.dll")] | |
| public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); | |
| [DllImport("user32.dll", SetLastError = true)] | |
| public static extern bool SetForegroundWindow(IntPtr hWnd); | |
| '@ -Name "Win32ShowWindowAsync" -Namespace Win32Functions -PassThru | |
| $handlesFilePath = "$env:APPDATA\WindowHandles.json" | |
| $global:MainWindowHandles = @{} | |
| if (Test-Path $handlesFilePath) { | |
| $json = Get-Content $handlesFilePath -Raw | |
| $data = $json | ConvertFrom-Json | |
| $currentTime = Get-Date | |
| foreach ($key in $data.PSObject.Properties.Name) { | |
| $handleData = $data.$key | |
| if ($handleData -and $handleData.Timestamp) { | |
| try { | |
| $timestamp = [datetime] $handleData.Timestamp | |
| if ($currentTime - $timestamp -lt (New-TimeSpan -Hours $ThresholdHours)) { | |
| $global:MainWindowHandles[[int] $key] = $handleData | |
| } | |
| } catch { | |
| Write-Verbose "Skipping invalid timestamp for handle $key" | |
| } | |
| } else { | |
| Write-Verbose "Skipping entry for handle $key due to missing data" | |
| } | |
| } | |
| } | |
| } | |
| Process { | |
| foreach ($process in $InputObject) { | |
| $handle = $process.MainWindowHandle | |
| if ($handle -eq 0 -and $global:MainWindowHandles.ContainsKey($process.Id)) { | |
| $handle = [int] $global:MainWindowHandles[$process.Id].Handle | |
| } | |
| if ($handle -eq 0) { | |
| if (-not $SuppressErrors) { | |
| Write-Error "Main Window handle is '0'" | |
| } else { | |
| Write-Verbose ("Skipping '{0}' with id '{1}', because Main Window handle is '0'" -f $process.ProcessName, $process.Id) | |
| } | |
| continue | |
| } | |
| Write-Verbose ("Processing '{0}' with id '{1}' and handle '{2}'" -f $process.ProcessName, $process.Id, $handle) | |
| $global:MainWindowHandles[$process.Id] = @{ | |
| Handle = $handle.ToString() | |
| Timestamp = (Get-Date).ToString("o") | |
| } | |
| $Win32ShowWindowAsync::ShowWindowAsync($handle, $WindowStates[$State]) | Out-Null | |
| if ($SetForegroundWindow) { | |
| $Win32ShowWindowAsync::SetForegroundWindow($handle) | Out-Null | |
| } | |
| Write-Verbose ("» Set Window State '{1}' on '{0}'" -f $handle, $State) | |
| } | |
| } | |
| End { | |
| $data = [ordered] @{} | |
| foreach ($key in $global:MainWindowHandles.Keys) { | |
| if ($global:MainWindowHandles[$key].Handle -ne 0) { | |
| $data["$key"] = $global:MainWindowHandles[$key] | |
| } | |
| } | |
| $json = $data | ConvertTo-Json | |
| Set-Content -Path $handlesFilePath -Value $json | |
| } | |
| } | 
@Nagidal added a flag for that too -SetForegroundWindow
Get-Process someprocess| Set-WindowState -State Show -SetForegroundWindow 
Hmm. When I do this, the program gets hidden, but it does not show again
Get-Process program | Set-WindowState -State Hide -SuppressErrors
then
Get-Process program | Set-WindowState -State Show -SuppressErrors
Any idea?
Hmm. When I do this, the program gets hidden, but it does not show again
Get-Process program | Set-WindowState -State Hide -SuppressErrorsthenGet-Process program | Set-WindowState -State Show -SuppressErrorsAny idea?
You need to execute those two commands in the same session. Otherwise it won't work, since a "hidden" application doesn't have a MainWindowHandle.
MainWindowHandles are now stored in a .json file, in "$env:APPDATA\WindowHandles.json", and restored them every time the script is run. At this point there is no automatic way to clear this file, only manually.
.json now includes a timestamp for each entry and invalidates them, if a threshold is reached (default is 24 hours).
Wow, two years later, you still added a feature. That's awesome!
And I just realized I didn't respond, sorry about that lol.
@Duoquadragesimal, yes it's because of the multiple processes, it should work though. You get an error for each process that doesn't have a main window. I added a
-SuppressErrorsflag, so you can call it like this: