我有一个使用out-gridview
显示结果的脚本。这是一个简单的例子:
"hello world" | out-gridview
当我使用使用PowerShell运行运行脚本时,它将打开gridview并在打开后立即关闭它。 (我认为这是因为gridview不是模态的,脚本完成了。)
如何让PowerShell等到手动关闭gridview?
答案 0 :(得分:7)
怎么样:
"hello world" | out-gridview -wait
根据the documentation of Out-GridView
,选项-Wait
会阻止Windows PowerShell关闭,直到Out-GridView窗口关闭。
它在Windows PowerShell 3.0中可用。
答案 1 :(得分:6)
我知道,老问题但是......
只需将'-PassThru'添加到Out-Gridview中 - 向gridview添加“OK”和“Cancel”按钮 - 现在您可以“使用powershell运行”并在完成后使用“确定”按钮关闭gridview窗口 - 太容易了!
答案 2 :(得分:4)
您可以使用-noexit
运行Powershell.exe,也可以尝试:
"hello world" | out-gridview
Read-Host "press enter to exit"
更新:
Out-GridView是非阻塞的,所以如果你想测试它退出,你必须求助于一些低级的Win32 API。以下代码适用于ISE(尚未在控制台主机中进行测试)。它也有一个限制 - 它基本上寻找与主机进程相关的任何窗口,而不是主机进程的主窗口。那时,它会回来。事实证明Out-GridView不是主窗口的子窗口,其标题不一致(GPS | Out-GridView或GPS | ogv或GPS | <any alias you make up>
):
$src = @'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace Utils
{
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
public class WindowHelper
{
private const int PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
private IntPtr _mainHwnd;
private IntPtr _ogvHwnd;
private IntPtr _poshProcessHandle;
private int _poshPid;
private bool _ogvWindowFound;
public WindowHelper()
{
Process process = Process.GetCurrentProcess();
_mainHwnd = process.MainWindowHandle;
_poshProcessHandle = process.Handle;
_poshPid = process.Id;
}
public void WaitForOutGridViewWindowToClose()
{
do
{
_ogvWindowFound = false;
EnumChildWindows(IntPtr.Zero, EnumChildWindowsHandler,
IntPtr.Zero);
Thread.Sleep(500);
} while (_ogvWindowFound);
}
[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(
IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
[DllImport("Oleacc.dll")]
public static extern IntPtr GetProcessHandleFromHwnd(IntPtr hwnd);
[DllImport("Kernel32.dll")]
public static extern int GetProcessId(IntPtr handle);
[DllImport("Kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DuplicateHandle(
IntPtr hSourceProcessHandle,
IntPtr hSourceHandle,
IntPtr hTargetProcessHandle,
out IntPtr lpTargetHandle,
int dwDesiredAccess,
bool bInheritHandle,
int dwOptions);
[DllImport("Kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr handle);
[DllImport("Kernel32.dll")]
public static extern int GetLastError();
private bool EnumChildWindowsHandler(IntPtr hwnd, IntPtr lParam)
{
if (_ogvHwnd == IntPtr.Zero)
{
IntPtr hProcess = GetProcessHandleFromHwnd(hwnd);
IntPtr hProcessDup;
if (!DuplicateHandle(hProcess, hProcess, _poshProcessHandle,
out hProcessDup,
PROCESS_QUERY_LIMITED_INFORMATION,
false, 0))
{
Console.WriteLine("Dup process handle {0:X8} error: {1}",
hProcess.ToInt32(), GetLastError());
return true;
}
int processId = GetProcessId(hProcessDup);
if (processId == 0)
{
Console.WriteLine("GetProcessId error:{0}",
GetLastError());
return true;
}
if (processId == _poshPid)
{
if (hwnd != _mainHwnd)
{
_ogvHwnd = hwnd;
_ogvWindowFound = true;
CloseHandle(hProcessDup);
return false;
}
}
CloseHandle(hProcessDup);
}
else if (hwnd == _ogvHwnd)
{
_ogvWindowFound = true;
return false;
}
return true;
}
}
}
'@
Add-Type -TypeDefinition $src
Get-Process | Out-GridView
$helper = new-object Utils.WindowHelper
$helper.WaitForOutGridViewWindowToClose()
"Done!!!!"
答案 3 :(得分:2)
Keith的解决方案因某些原因对我不起作用。当我运行它时,我得到错误,并且该过程终止而不等待网格关闭。我得到这样的输出:
...
GetProcessId error:6
Dup process handle 0000015C error: 6
GetProcessId error:6
GetProcessId error:6
Dup process handle 00000148 error: 6
GetProcessId error:6
GetProcessId error:6
...
我真的不太了解Keith解决方案中使用的Windows API。但经过一番挖掘,我确实找到了一种方法来修改更简单的解决方案。它涉及较少的API调用和导入,也不会产生任何错误。这就是我想出来的。
$src = @'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace Utils
{
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
public class WindowHelper
{
private const int PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
private IntPtr _mainHwnd;
private IntPtr _ogvHwnd;
private IntPtr _poshProcessHandle;
private int _poshPid;
private bool _ogvWindowFound;
public WindowHelper()
{
Process process = Process.GetCurrentProcess();
_mainHwnd = process.MainWindowHandle;
_poshProcessHandle = process.Handle;
_poshPid = process.Id;
}
public void WaitForOutGridViewWindowToClose()
{
do
{
_ogvWindowFound = false;
EnumChildWindows(IntPtr.Zero, EnumChildWindowsHandler,
IntPtr.Zero);
Thread.Sleep(500);
} while (_ogvWindowFound);
}
[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(
IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
[DllImport("User32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId);
[DllImport("Kernel32.dll")]
public static extern int GetLastError();
private bool EnumChildWindowsHandler(IntPtr hwnd, IntPtr lParam)
{
if (_ogvHwnd == IntPtr.Zero)
{
int processId;
int thread = GetWindowThreadProcessId(hwnd, out processId);
if (processId == 0)
{
Console.WriteLine("GetWindowThreadProcessId error:{0}",
GetLastError());
return true;
}
if (processId == _poshPid)
{
if (hwnd != _mainHwnd)
{
_ogvHwnd = hwnd;
_ogvWindowFound = true;
return false;
}
}
}
else if (hwnd == _ogvHwnd)
{
_ogvWindowFound = true;
return false;
}
return true;
}
}
}
'@
Add-Type -TypeDefinition $src
Get-Process | Out-GridView
$helper = new-object Utils.WindowHelper
$helper.WaitForOutGridViewWindowToClose()
希望这会使其他人免于我遇到的同样问题。