A friend has a problem on his work PC. There are frequent network issues, after which he sees dozens of error popup windows from File Explorer. He wants a PowerShell script to close them all down without having to click each one individually. I solved the problem in Python but he must have a PowerShell script and I'm a PowerShell novice.
I found this example: https://stackoverflow.com/questions/64469727/powershell-and-winapi-enumwindows-function
and I cobbled together the following script, to help me understand what I need to do.
function Get-ChildWindowHandles {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[IntPtr]$ParentWindowHandle
)
$MemberDefinition = @"
// declare the EnumChildWindowsProc delegate type
public delegate bool EnumChildWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool EnumChildWindows(IntPtr hWnd, EnumChildWindowsProc enumProc, IntPtr lParam);
"@
Add-Type -MemberDefinition $MemberDefinition -Name EnumChildWindowsUtil -Namespace Win32Functions
# Create a list to act as a receptacle for all the window handles we're about to enumerate
$ChildWindowHandles = [System.Collections.Generic.List[IntPtr]]::new()
# Define the callback function
$callback = {
param([IntPtr]$handle, [IntPtr]$param)
# Copy the window handle to our list
$ChildWindowHandles.Add($handle)
# Continue (return $false from the callback to abort the enumeration)
return $true
}
[Win32Functions.EnumChildWindowsUtil]::EnumChildWindows($ParentWindowHandle, $callback, [IntPtr]::Zero)
return $ChildWindowHandles
}
$com_object = New-Object -com "Shell.Application"
$windows = $com_object.windows()
foreach ($w in $windows) {
if ($w.Name -eq 'File Explorer') {
$handles = Get-ChildWindowHandles -ParentWindowHandle $w.HWND
foreach ($handle in $handles) {
Write-Output "handle.GetType $($handle.GetType()) handle $($handle)"
}
}
}
It returns this:
handle.GetType bool handle True
handle.GetType System.IntPtr handle 591506
handle.GetType System.IntPtr handle 591192
handle.GetType System.IntPtr handle 722370
...
Why is the first element a boolean? I'd be very grateful if someone could explain what I'm doing wrong.
As an aside, why aren't File Explorer windows seen when I try
Get-Process | Where-Object {$_.MainWindowTitle} #| Select-Object MainWindowTitle
?
Thanks in advance for any help Chris
EnumChildWindows
returns a BOOL
according to https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumchildwindows:
BOOL EnumChildWindows(
^^^^
[in, optional] HWND hWndParent,
[in] WNDENUMPROC lpEnumFunc,
[in] LPARAM lParam
);
That return value isn't being captured in your function so it's being returned implicitly as part of the function's output stream.
You can capture it with:
$null = [Win32Functions.EnumChildWindowsUtil]::EnumChildWindows( ... )
^^^^^^^
and it'll no longer appear in the function return values.
Other options to do the same thing are:
[void] [Win32Functions.EnumChildWindowsUtil]::EnumChildWindows( ... )
^^^^^^
or
[Win32Functions.EnumChildWindowsUtil]::EnumChildWindows( ... ) | Out-Null
^^^^^^^^^^
but $null =
is my own personal stylistic preference