Created
October 21, 2025 14:12
-
-
Save valen214/97ff856481bf6cfc1120d7440e1e4386 to your computer and use it in GitHub Desktop.
restart windows explorer.exe from powershell with Windows Restart Manager API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # restart-explorer.ps1 | |
| # Restarts explorer.exe using Windows Restart Manager. | |
| Add-Type -TypeDefinition @" | |
| using System; | |
| using System.Runtime.InteropServices; | |
| using System.Text; | |
| [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] | |
| public struct RM_UNIQUE_PROCESS | |
| { | |
| public int dwProcessId; | |
| public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; | |
| } | |
| // https://learn.microsoft.com/en-us/windows/win32/api/restartmanager/ns-restartmanager-rm_process_info | |
| [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] | |
| public struct RM_PROCESS_INFO | |
| { | |
| public RM_UNIQUE_PROCESS Process; | |
| [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] | |
| public string strAppName; | |
| [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] | |
| public string strServiceShortName; | |
| public uint ApplicationType; | |
| public uint AppStatus; | |
| public uint TSSessionId; | |
| [MarshalAs(UnmanagedType.Bool)] | |
| public bool bRestartable; | |
| } | |
| // omitted RmGetFilterList RmAddFilter RmJoinSession RmCancelCurrentTask | |
| public static class RestartManager | |
| { | |
| [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] | |
| public static extern int RmStartSession( | |
| out int pSessionHandle, | |
| int dwSessionFlags, | |
| StringBuilder strSessionKey | |
| ); | |
| [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] | |
| public static extern int RmRegisterResources( | |
| int dwSessionHandle, | |
| uint nFiles, | |
| [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgsFiles, | |
| uint nApplications, | |
| IntPtr rgApplications, // not used | |
| uint nServices, | |
| IntPtr rgsServiceNames // not used | |
| ); | |
| [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] | |
| public static extern int RmGetList( | |
| int dwSessionHandle, | |
| out uint pnProcInfoNeeded, | |
| ref uint pnProcInfo, | |
| [In, Out] RM_PROCESS_INFO[] rgAffectedApps, | |
| out uint lpdwRebootReasons | |
| ); | |
| [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] | |
| public static extern int RmShutdown( | |
| int dwSessionHandle, | |
| uint lActionFlags, | |
| IntPtr fnStatus // callback not used | |
| ); | |
| [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] | |
| public static extern int RmRestart( | |
| int dwSessionHandle, | |
| uint lActionFlags, | |
| IntPtr fnStatus // callback not used | |
| ); | |
| [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] | |
| public static extern int RmEndSession(int dwSessionHandle); | |
| } | |
| "@ -ErrorAction Stop | |
| function Restart-Explorer { | |
| # Constants | |
| $RM_SESSION_KEY_LEN = 32 | |
| # Prepare session | |
| $sessionHandle = 0 | |
| $sessionKey = New-Object System.Text.StringBuilder ($RM_SESSION_KEY_LEN + 1) | |
| # Start session | |
| $start = [RestartManager]::RmStartSession([ref]$sessionHandle, 0, $sessionKey) | |
| if ($start -ne 0) { | |
| throw "RmStartSession failed with error code $start" | |
| } | |
| try { | |
| # Register explorer.exe by full path | |
| $explorerPath = Join-Path $env:WINDIR 'explorer.exe' | |
| $files = @($explorerPath) | |
| $reg = [RestartManager]::RmRegisterResources( | |
| $sessionHandle, [uint32]$files.Count, $files, 0, [IntPtr]::Zero, 0, [IntPtr]::Zero | |
| ) | |
| if ($reg -ne 0) { | |
| throw "RmRegisterResources failed with error code $reg" | |
| } | |
| $needed = 0 | |
| $count = 0 | |
| $reasons = 0 | |
| # First call to get required size | |
| $result = [RestartManager]::RmGetList($handle, [ref]$needed, [ref]$count, $null, [ref]$reasons) | |
| if ($result -eq 234) { # 234 == ERROR_MORE_DATA | |
| $array = New-Object RM_PROCESS_INFO[] $needed | |
| $count = $needed | |
| $result = [RestartManager]::RmGetList($handle, [ref]$needed, [ref]$count, $array, [ref]$reasons) | |
| if ($result -eq 0) { | |
| Write-Host "Porcesses using Explorer.exe" | |
| foreach ($proc in $array) { | |
| Write-Host "Process: $($proc.strAppName) (PID=$($proc.Process.dwProcessId))" | |
| } | |
| } | |
| } | |
| # Request shutdown of explorer (no special flags) | |
| $sh = [RestartManager]::RmShutdown($sessionHandle, 0, [IntPtr]::Zero) | |
| if ($sh -ne 0) { | |
| throw "RmShutdown failed with error code $sh" | |
| } | |
| Start-Sleep -Milliseconds 500 | |
| # Request restart of explorer | |
| $rs = [RestartManager]::RmRestart($sessionHandle, 0, [IntPtr]::Zero) | |
| if ($rs -ne 0) { | |
| throw "RmRestart failed with error code $rs" | |
| } | |
| Write-Host "Explorer restarted via Restart Manager. SessionKey=$($sessionKey.ToString())" | |
| } finally { | |
| # End session | |
| [void][RestartManager]::RmEndSession($sessionHandle) | |
| } | |
| } | |
| # Execute | |
| Restart-Explorer | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment