Skip to content

Instantly share code, notes, and snippets.

@lalibi
Forked from Nora-Ballard/Set-WindowState.ps1
Last active August 26, 2023 04:25
Show Gist options
  • Star 27 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save lalibi/3762289efc5805f8cfcf to your computer and use it in GitHub Desktop.
Save lalibi/3762289efc5805f8cfcf to your computer and use it in GitHub Desktop.
Hide, Show, Minimize, Maximize, etc window from Powershell.
function Set-WindowState {
<#
.LINK
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
)
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
if (!$global:MainWindowHandles) {
$global:MainWindowHandles = @{ }
}
}
Process {
foreach ($process in $InputObject) {
$handle = $process.MainWindowHandle
if ($handle -eq 0 -and $global:MainWindowHandles.ContainsKey($process.Id)) {
$handle = $global:MainWindowHandles[$process.Id]
}
if ($handle -eq 0) {
if (-not $SuppressErrors) {
Write-Error "Main Window handle is '0'"
}
continue
}
$global:MainWindowHandles[$process.Id] = $handle
$Win32ShowWindowAsync::ShowWindowAsync($handle, $WindowStates[$State]) | Out-Null
if ($SetForegroundWindow) {
$Win32ShowWindowAsync::SetForegroundWindow($handle) | Out-Null
}
Write-Verbose ("Set Window State '{1} on '{0}'" -f $MainWindowHandle, $State)
}
}
}
@lalibi
Copy link
Author

lalibi commented Oct 27, 2015

Corrected issues with illegal characters and added pipeline support.

@CDWilliams05
Copy link

I'm having an issue with using your inputobject. It's telling me that its null when I run this from a piped "Get-Process"

@ed1chandler
Copy link

Question: Once you "HIDE" a window, its MainWindowHandle becomes 0, ... so how do you make it visible again?
Start-Process 'notepad.exe' # Start notepad.
$hwndBefore = (Get-Process -Name 'notepad').MainWindowHandle # Get main window handle.
Set-WindowStyle -MainWindowHandle $hwndBefore -Style HIDE # Hide it.
$hwndAfter = (Get-Process -Name 'notepad').MainWindowHandle # Handle now = 0
Set-WindowStyle -MainWindowHandle $hwndAfter -Style SHOW # No effect

@Inventologist
Copy link

@ed1chandler

Modify the code so that BEFORE you minimize it, you store info about the process (PID or ProcessName). That way you can reference it.

@dearZander
Copy link

Thanks, Dude, working like a charm on Windows 8, I need the alt - tab simulation but I was able to solve my issue minimizing the unwanted app and bring to the front the desired app.

@chaoscreater
Copy link

chaoscreater commented Aug 30, 2019

I can't seem to restore a minimized window. Can someone post an example code on how to achieve this?

After the window is minimized, if I do this:
$hwndAfter = (Get-Process -Name 'notepad').MainWindowHandle

I can get the mainwindowhandle just fine. So why Can't I just do this?
Set-WindowStyle -MainWindowHandle $hwndAfter -Style RESTORE

OR this:
Set-WindowStyle -MainWindowHandle $hwndAfter -Style SHOW

?

@lalibi
Copy link
Author

lalibi commented Nov 17, 2019

@chaoscreater RESTORE should work after you minimize a window. It doesn't work when you use HIDE, where MainWindowHandle becomes 0.

@lalibi
Copy link
Author

lalibi commented Nov 18, 2019

Updated the code so that it keeps the MainWindowHandle of the processes (for the current session) it handles. So now (in the same session) you can HIDE and then SHOW a window.

The implementation is not that elegant at the moment, it pollutes the global space with a variable (MainWindowHandle)

@chaoscreater
Copy link

chaoscreater commented Dec 3, 2019

Updated the code so that it keeps the MainWindowHandle of the processes (for the current session) it handles. So now (in the same session) you can HIDE and then SHOW a window.

The implementation is not that elegant at the moment, it pollutes the global space with a variable (MainWindowHandle)

@lalibi

Hi, thanks for updating the script. I can't figure out how to use it, I'm getting the following error:

Cannot convert argument "hWnd", with value: "", for "ShowWindowAsync" to type "System.IntPtr": "Cannot convert null to type "System.IntPtr"."

Could you provide an example of how to restore a minimized window please?

Update:

Nevermind, I got it.

$inputobject = get-process -name 'notepad'
Set-WindowState -inputObject $inputobject -State RESTORE

@lalibi
Copy link
Author

lalibi commented Dec 21, 2019

Or like this:

Get-Process notepad | Set-WindowState -State Hide
Get-Process notepad | Set-WindowState -State Show

@Duoquadragesimal
Copy link

Keep getting error "Main Window handle is '0' " when trying to run this on spotify, works Fine on notepad though. Maybe something to do with how spotify seems to be made up of 3 processes in task manager.
Image attached to show what I mean.
https://i.ibb.co/71nqXhx/Capture69.jpg

@fleetingbytes
Copy link

It's good, but although it sets the correct window state on the correct handle, what is still missing in certain $States is a command to bring the window to the foreground, e.g. $Win32ShowWindowAsync::SetForegroundWindow($handle) | Out-Null

@lalibi
Copy link
Author

lalibi commented Dec 27, 2021

@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 -SuppressErrors flag, so you can call it like this:

Get-Process spotify | Set-WindowState -State Show -SuppressErrors
Get-Process spotify | Set-WindowState -State Hide -SuppressErrors

@lalibi
Copy link
Author

lalibi commented Dec 27, 2021

@Nagidal added a flag for that too -SetForegroundWindow

Get-Process someprocess| Set-WindowState -State Show -SetForegroundWindow 

@DasGandlaf
Copy link

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?

@lalibi
Copy link
Author

lalibi commented Jun 14, 2022

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?

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment