See the question and my original answer on StackOverflow

Well, I can reproduce "sometimes"... It's strange but here is a workaround that should work, it uses IWebBrowser2::HWND and PostMessage asking the owner window to close:

var staThread = new Thread(() =>
{
    var shellType = Type.GetTypeFromCLSID(new Guid("9BA05972-F6A8-11CF-A442-00A0C90A8F39"))!;
    dynamic shellWindows = Activator.CreateInstance(shellType!)!;

    // we need to loop here because some windows may not close immediately
    do
    {
        var toClose = new List<dynamic>();
        foreach (var window in shellWindows)
        {
            // add your logic here...
            toClose.Add(window);
        }
        if (toClose.Count == 0)
            break;

        foreach (var window in toClose)
        {
            nint hwnd;
            try
            {
                hwnd = (nint)window.HWND;
            }
            catch
            {
                continue;
            }

            const uint WM_CLOSE = 0x0010;
            PostMessage(hwnd, WM_CLOSE, 0, 0);
        }
    } while (true);
});

staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();

[DllImport("user32")]
public static extern nint PostMessage(nint hWnd, uint Msg, nint wParam, nint lParam);

PS: your definition of IShellWindows is useless since you use dynamic (IDispatch undercovers).