Windows – Find all window titles of application through command line

batch filecommand lineprocesswindows

In Windows if I want to list all instances (and window titles) of a given application from the command line I run this command:

tasklist /fi "IMAGENAME eq notepad.exe" /v

However I can't do the same thing for applications such as LibreOffice. For example no matter how many different Writer windows I may have open, there always is only one soffice.bin and one soffice.exe process. Using the tasklist command I can only see one window title associated with soffice.bin process.

Same thing happens with Microsoft Word (only one winword.exe process exists and is associated with only one window title).

Is there any way I can list all the window titles of such applications through the command line?

Best Answer

You can use the following PowerShell script:

Add-Type  @"
    using System;
    using System.Runtime.InteropServices;
    using System.Text;    
    public class Win32 {
        public delegate void ThreadDelegate(IntPtr hWnd, IntPtr lParam);
        
        [DllImport("user32.dll")]
        public static extern bool EnumThreadWindows(int dwThreadId, 
            ThreadDelegate lpfn, IntPtr lParam);
        
        [DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public static extern int GetWindowText(IntPtr hwnd, 
            StringBuilder lpString, int cch);
        
        [DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public static extern Int32 GetWindowTextLength(IntPtr hWnd);

        [DllImport("user32.dll")]
        public static extern bool IsIconic(IntPtr hWnd);

        [DllImport("user32.dll")]
        public static extern bool IsWindowVisible(IntPtr hWnd);

        public static string GetTitle(IntPtr hWnd) {
            var len = GetWindowTextLength(hWnd);
            StringBuilder title = new StringBuilder(len + 1);
            GetWindowText(hWnd, title, title.Capacity);
            return title.ToString();
        }
    }
"@

$windows = New-Object System.Collections.ArrayList
Get-Process | Where { $_.MainWindowTitle } | foreach {
    $_.Threads.ForEach({
        [void][Win32]::EnumThreadWindows($_.Id, {
            param($hwnd, $lparam)
            if ([Win32]::IsIconic($hwnd) -or [Win32]::IsWindowVisible($hwnd)) {
                $windows.Add([Win32]::GetTitle($hwnd))
            }}, 0)
        })}
Write-Output $windows

I wrote a program that allows filtering this list and brings the selected window to the front: activatewindow