从PowerShell启动时如何正确关闭Internet Explorer?

Ves*_*per 8 com powershell internet-explorer

有一组最近被问到的关于通过PowerShell使用Internet Explorer做一些事情的问题.所有这些都包含从PowerShell作为对象启动IE的代码$ie=new-object -comobject InternetExplorer.Application.问题是,关闭由调用组成的IE 的正确方法$ie.quit()不起作用 - 首先,如果IE碰巧有多个单独的打开选项卡,IE不会作为一个整体退出,只有对应的选项卡COM对象关闭,其次,如果它只有一个选项卡,则窗口关闭但进程仍然存在.

PS > get-process iexplore

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    352      31     7724      24968   142     0,58   3236 iexplore
    228      24    22800      15384   156     0,19   3432 iexplore
Run Code Online (Sandbox Code Playgroud)

我试图研究如何关闭一个进程启动的方法New-Object -ComObject,并找到了:如何摆脱COMObject.COMObject的示例Excel.Application实际上表现如预期 - 调用quit()使窗口关闭,并且执行[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ex)if $ex是创建的COMObject会停止Excel进程.但是Internet Explorer不是这种情况.

我还发现了这个问题:如何获取正在运行的IE的现有COM对象,它提供了通过打开的窗口列表连接到IE的代码,并且工作到从其他地方启动的IE的程度,但是如果COM对象是通过PowerShell创建的,此脚本无法完全停止IE的进程,如果这样修改:

$shellapp = New-Object -ComObject "Shell.Application"
$ShellWindows = $shellapp.Windows()
for ($i = 0; $i -lt $ShellWindows.Count; $i++)
{
 if ($ShellWindows.Item($i).FullName -like "*iexplore.exe")
  {
  $ie = $ShellWindows.Item($i)
  $ie.quit()
  [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ie)
  }
}
Run Code Online (Sandbox Code Playgroud)

如果在PowerShell之外启动IE,则会停止进程,但是如果在PowerShell中启动IE,则会保留两个进程,并且此代码报告找不到IE窗口来访问COM对象,因此IE进程(还)无法进行要停下来

那么,如何到达显然孤立的无窗口IE进程并优雅地阻止它们?我知道Get-Process iexplore | Stop-Process,但是这将阻止任何和所有IE,而不仅仅是脚本启动的IE,如果脚本以管理员或SYSTEM远程桌面服务器的形式运行,那么每个人的IE都将被停止.

环境:OS Windows 7 x64,PowerShell 4(安装在PS版本2上方),IE11版本11.0.9600.17691(自动更新).IE在启动时设置为"打开主页",因此至少有一个选项卡始终打开.

Ans*_*ers 9

简单地调用该Quit()方法通常应该足以优雅地终止Internet Explorer进程,无论它们是通过运行iexplore.exe还是通过在PowerShell中实例化COM对象来创建的.

示范:

PS C:\> $env:PROCESSOR_ARCHITECTURE
AMD64
PS C:\> (Get-WmiObject -Class Win32_OperatingSystem).Caption
Microsoft Windows 8.1 Enterprise
PS C:\> Get-Process | ? { $_.ProcessName -eq 'iexplore' }
PS C:\> $ie = New-Object -COM 'InternetExplorer.Application'
PS C:\> Get-Process | ? { $_.ProcessName -eq 'iexplore' }

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    352      20     4244      14164   176     0.05   3460 iexplore
    407      32     6428      23316   182     0.23   5356 iexplore

PS C:\> $ie.Quit()
PS C:\> Get-Process | ? { $_.ProcessName -eq 'iexplore' }
PS C:\> _

如果您有孤立的Internet Explorer进程,您没有句柄,您可以像这样循环:

(New-Object -COM 'Shell.Application').Windows() | Where-Object {
    $_.Name -like '*Internet Explorer*'
} | ForEach-Object {
    $_.Quit()
}
Run Code Online (Sandbox Code Playgroud)

为了完全安全起见,您可以在调用后释放COM对象Quit(),然后等待垃圾收集器清理:

(New-Object -COM 'Shell.Application').Windows() | Where-Object {
    $_.Name -like '*Internet Explorer*'
} | ForEach-Object {
    $_.Quit()
    [Runtime.Interopservices.Marshal]::ReleaseComObject($_)
}

[GC]::Collect()
[GC]::WaitForPendingFinalizers()
Run Code Online (Sandbox Code Playgroud)