I did some powershell scripting these days.
Someone asked me if it would be possible to avoid the user to close the powershell window while a script is running (logon or any other). After a few searches in the MSDN world, I was able to handle the window and send some parameters to it.
For this, I ask the user32.dll Library to disable the powershell window and to disable the button (close menu). To remove any undesired button, I set the Windows style to Toolbox.
I know the fact of disabling window will avoid any user input and click on any button, but as they asked me to disable the button, I dit it this way. So use the rest as know-how… 🙂
Knowing what I need to code, I will use some user32.dll methods :
- GetSytemMenu
- EnableMenuItem
- SetWindowLongPtr
- EnableWindow
Hope that this script can be useful to some admins!
Karl
Windows versions tested | |
Windows 2000 | – |
Windows XP | – |
Windows 7 | OK |
Windows 8 | – |
Windows 8.1 Standard | OK (Disabled window only) |
Here is the script :
#Calling user32.dll methods for Windows and Menus
$MethodsCall = '
[DllImport("user32.dll")] public static extern long GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")] public static extern bool EnableMenuItem(long hMenuItem, long wIDEnableItem, long wEnable);
[DllImport("user32.dll")] public static extern long SetWindowLongPtr(long hWnd, long nIndex, long dwNewLong);
[DllImport("user32.dll")] public static extern bool EnableWindow(long hWnd, int bEnable);
'
#Create a new namespace for the Methods to be able to call them
Add-Type -MemberDefinition $MethodsCall -name NativeMethods -namespace Win32
#WM_SYSCOMMAND Message
$MF_GRAYED = 0x00000001L #Indicates that the menu item is disabled and grayed so that it cannot be selected.
$MF_BYCOMMAND = 0x0 #Gives the identifier of the menu item. If neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified, the MF_BYCOMMAND flag is the default flag.
$MF_DISABLED = 0x00000002L #Indicates that the menu item is disabled, but not grayed, so it cannot be selected.
$MF_ENABLED = 0x00000000L #Indicates that the menu item is enabled and restored from a grayed state so that it can be selected.
#... http://msdn.microsoft.com/en-us/library/windows/desktop/ms647636(v=vs.85).aspx
$SC_CLOSE = 0xF060
$SC_CONTEXTHELP = 0xF180
$SC_MAXIMIZE = 0xF030
$SC_MINIMIZE = 0xF020
$SC_TASKLIST = 0xF130
$SC_MOUSEMENU = 0xF090
$SC_KEYMENU = 0xF100
#... http://msdn.microsoft.com/en-us/library/windows/desktop/ms646360(v=vs.85).aspx
$GWL_EXSTYLE = -20
$GWL_STYLE = -16
#... http://msdn.microsoft.com/en-us/library/windows/desktop/ms644898(v=vs.85).aspx
#WM_SETICON Message - http://msdn.microsoft.com/en-us/library/ms632643%28VS.85%29.aspx
$WM_SETICON = 0x0080;
$ICON_SMALL = 0;
$ICON_BIG = 1;
#Extended Window Styles
$WS_EX_DLGMODALFRAME = 0x00000001L
$WS_EX_NOACTIVATE = 0x08000000L
$WS_EX_TOOLWINDOW = 0x00000080L
$WS_EX_STATICEDGE = 0x00020000L
$WS_EX_WINDOWEDGE = 0x00000100L
$WS_EX_TRANSPARENT = 0x00000020L
$WS_EX_CLIENTEDGE = 0x00000200L
$WS_EX_LAYERED = 0x00080000
$WS_EX_TOPMOST = 0x00000008L
#... http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx
#Get window handle of Powershell process (Ensure there is only one Powershell window opened)
$PSWindow = (Get-Process Powershell) | where {$_.MainWindowTitle -like "*Powershell*"}
$hwnd = $PSWindow.MainWindowHandle
#Get System menu of windows handled
$hMenu = [Win32.NativeMethods]::GetSystemMenu($hwnd, 0)
#Window Style : TOOLWINDOW
[Win32.NativeMethods]::SetWindowLongPtr($hwnd, $GWL_EXSTYLE, $WS_EX_TOOLWINDOW) | Out-Null
#Disable X Button and window itself
[Win32.NativeMethods]::EnableMenuItem($hMenu, $SC_CLOSE, $MF_DISABLED) | Out-Null
[Win32.NativeMethods]::EnableWindow($hwnd, 0) | Out-Null
Write-Host "Disabled!" -ForegroundColor Red
sleep 5
#Enable X Button
[Win32.NativeMethods]::EnableMenuItem($hMenu, $SC_CLOSE, $MF_ENABLED) | Out-Null
[Win32.NativeMethods]::EnableWindow($hwnd, 1) | Out-Null
Write-Host "Enabled!" -ForegroundColor Green
sleep 2