Home > OS >  How to enumerate the real Windows File Explorer windows
How to enumerate the real Windows File Explorer windows

Time:09-29

I'm trying to enumerates all open File Explorer windows in a PowerShell script.
I have already found on other posts how to enumerate all explorer.exe windows instances, for example using the Shell.Application COM API:

(New-Object -com "Shell.Application").windows()

But this actually returns more than I want:
I want only the "real" File Explorer windows showing actual files on my disk or network, not the "fake" explorer.exe instances that are just containers for various Control Panel windows, etc.
So basically the list of instances shown when hovering the mouse over the File Explorer icon on the Taskbar.
How can this be done reliably, and preferably in a way that works in Windows 7 to 11?

  • Comparing the window title to known strings like "Control Panel" or "Windows Update" has limited value. This would only eliminate the most common cases, and on English versions of Windows only.
  • I tried looking at the File Explorer window class, but it's "CabinetWClass" in all cases, even for Control Panels.
  • I noticed that real instances have a child window of class "UIRibbonWorkPane", whereas the Control Panel does not. But the ribbon can be disabled, so this is not a reliable marker.

My script already contains C# declarations encapsulating WIN32 API calls, so C# code snippets would also do.

CodePudding user response:

It seems that only file-path-based File Explorer windows have a non-$null .LocationUrl property value, so you can filter by that:

$explorerWinsWithFilePaths = 
  (New-Object -com "Shell.Application").Windows() | Where-Object LocationUrl

To extract the file paths that these windows are displaying (the technique also works with non-file locations such as Quick Access, which translate into ::-prefixed GUIDs):

$explorerWinsWithFilePaths.Document.Folder.Self.Path

CodePudding user response:

One solution is to test whether the Shell Folder (IShellFolder) beneath the Shell View that Windows sends back is handled by the Windows file system or by some custom folder.

For that, you can use the System.NamespaceCLSID Windows property. If the folder associated with the view is handled by the file system, this property value will be the ShellFSFolder GUID value which equal to f3364ba0-65b9-11ce-a9ba-00aa004ae837 (from Windows SDK shobjidl_core.h).

You can test it with something like this in PowerShell:

$ShellFSFolder = [System.Guid]::New("f3364ba0-65b9-11ce-a9ba-00aa004ae837")

foreach($win in (New-Object -com "Shell.Application").Windows()) {
    $clsid = $win.Document.Folder.Self.ExtendedProperty("System.NamespaceCLSID")
    if ($clsid -ne $null) {
        $clsid = [System.Guid]::New($clsid)
        if ($clsid -eq $ShellFSFolder) {
            Write-Host $win.Document.Folder.Self.Path
        }
    }
}

And like this in C#:

var ShellFSFolder = new Guid("f3364ba0-65b9-11ce-a9ba-00aa004ae837");

dynamic shell = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
foreach (var win in shell.Windows)
{
    var clsid = win.Document.Folder.Self.ExtendedProperty("System.NamespaceCLSID");
    if (clsid != null)
    {
        Guid guid;
        if (clsid is byte[] bytes)
        {
            guid = new Guid(bytes);
        }
        else
        {
            guid = new Guid((string)clsid);
        }
        
        if (guid == ShellFSFolder)
        {
            Console.WriteLine(win.Document.Folder.Title); // for example
        }
    }
}
  • Related