0

I want that a Out-GridView closes after a specific time, e.g after 10 seconds.

Not used to the windows powershell.

Any answer helps.

anthony sottile
  • 61,815
  • 15
  • 148
  • 207
gitgudgithub
  • 167
  • 1
  • 2
  • 7
  • 1
    Why? What problem are you actually trying to solve where you need `Out-GridView` to close on a timer? There might be better solutions to whatever you're trying to do... – notjustme Jul 26 '18 at 15:25
  • actually i only need to know how to close a outgridview with a command so i don't need to press the x button. – gitgudgithub Jul 26 '18 at 16:03

1 Answers1

1

Unfortunately, PowerShell doesn't natively offer finding and closing arbitrary GUI windows, but you can use the Add-Type cmdlet with ad hoc-compiled C# code that in turn uses P/Invoke declarations to access the Windows API.

The following is a working example:

  • It defines a distinct window title to use for the Out-GridView call so that the window can be (hopefully) unambiguously located by its title later; also the assumption is that only one window by that title exists.

    • To make this more robust by limiting the window search to the same process, ... would require quite a bit of extra work.
  • It creates a background job that uses Add-Member to define a static helper class with a method for closing a window by its title, and calls it after a specifiable timeout.

  • It invokes Out-GridView synchronously (blocking) with -Wait, using the specified window title. If the window is left open for the specified timeout period, the background job will automatically close it.

  • It removes the background job after the window has closed.

Note: If you don't need the Out-GridView call to be synchronous, you wouldn't necessarily need a background job.

# Define a distinct window title that you expect no other window to have.
$title = 'Close Me'

# Start a background job that closes the window after a specified timeout.
$job = Start-Job { 

  param($timeout, $title)

  # Define a helper class that uses the Windows API to find and close windows.
  Add-Type -Namespace same2u.net -Name WinUtil -MemberDefinition @'

  // P/Invoke declarations for access to the Windows API.
  [DllImport("user32.dll", SetLastError=true)]
  private static extern IntPtr FindWindow(string lpszClass, string lpszWindow);

  [DllImport("user32.dll", SetLastError=true)]
  private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
  const UInt32 WM_CLOSE = 0x0010;

  // Returns the hWnd (window handle) of the first window that matches the 
  // specified title and, optionally, window class.
  // If none is found, IntPtr.Zero is returned, which can you test for with -eq 0
  public static IntPtr GetWindowHandle(string title, string className = null) {
    // As a courtesy, we interpet '' as null, because passing null from
    // PowerShell requires the non-obvious [nullstring]::value.
    if (className == "") { className = null; }
    return FindWindow(className, title);
  }

  // Closes the first window that matches the specified title and, optionally,
  // window class. Returns true if a windows found and succesfully closed.
  public static bool CloseWindow(string title, string className = null) {
    bool ok = false;
    // As a courtesy, we interpet '' as null, because passing null from
    // PowerShell requires the non-obvious [nullstring]::value.
    if (className == "") { className = null; }
    IntPtr hwnd = FindWindow(className, title);
    if (hwnd != IntPtr.Zero) {
      SendMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
      // !! SendMessage seemingly always returns 0. To determine success,
      // !! we simply test if the window still exists.
      ok = IntPtr.Zero == FindWindow(className, title);
    }
    return ok;
  }

'@

  Start-Sleep $timeout
  $null = [same2u.net.WinUtil]::CloseWindow($title)

} -ArgumentList 3, $title


# Open an Out-GridView window synchronously.
# If you leave it open, the background job will close it after 3 seconds.
1..10 | Out-GridView -Title $title -Wait

# Remove the background job; -Force is needed in case the job hasn't finished yet
# (if you've closed the window manually before the timeout).
Remove-Job -Force $job
mklement0
  • 382,024
  • 64
  • 607
  • 775