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

时间:2015-06-04 11:39:25

标签: internet-explorer powershell com

最近有一些关于通过PowerShell使用Internet Explorer做一些事情的问题。所有这些代码都包含通过$ie=new-object -comobject InternetExplorer.Application从PowerShell作为对象启动IE的代码。问题是,关闭包含调用$ie.quit()的IE的正确方法不起作用 - 首先,如果IE碰巧有多个打开的标签,IE就不会t作为一个整体退出,只关闭与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

我尝试研究如何关闭通过New-Object -ComObject启动的流程的方法,并找到了这个:How to get rid of a COMObject。 COMObject的示例是Excel.Application,它确实按预期运行 - 调用quit()使窗口关闭,如果[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ex)是创建的COMObject,则执行$ex将停止Excel进程。但是Internet Explorer并非如此。

我也发现了这个问题:How to get existing COM Object of a running IE提供了通过打开的窗口列表连接到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)
  }
}

如果在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在启动时设置为“打开主页”,因此至少有一个选项卡始终打开。

6 个答案:

答案 0 :(得分:7)

简单地调用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()
}

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

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

[GC]::Collect()
[GC]::WaitForPendingFinalizers()

答案 1 :(得分:2)

我遇到了与使用quit()方法无法终止的COM对象类似的问题。 Interopservices.marshall也不会工作很多次。 我的解决方法:在调用com对象之前和之后,我执行get-process来获取所有proc的列表:这样我就拥有了我的实例的PID。运行脚本后,它会使用stop-process终止进程。

不是最好的方法,但至少它可行

答案 2 :(得分:1)

通过快速浏览ComObject for IE,似乎在创建它时,它为您提供了一个直接接口,使得与IE交互的方法更容易,例如Navigate()或{{1} }。

我确实发现了一个似乎正在寻找的属性,那将是ReadyState

调用Parent似乎摆脱了PowerShell创建的实例。

$IE.Parent.Quit()

答案 3 :(得分:0)

HKCU\Software\Microsoft\Internet Explorer\Main\FrameMerging个注册表项阻止合并IE" frame"流程,explained here。我自己没有尝试过,但我认为如果在实例化InternetExplorer.Application COM对象之前将其设置为,它可能会解决您的问题。

如果这没有帮助,请尝试使用以下命令行 previous 启动新的IE实例来创建COM对象(我还没试过):

  • iexplore.exe -noframemerging -private -embedding

在此IE实例作为COM服务器可用之前可能存在竞争条件,因此您可能希望在创建对象之前放置一些延迟。

答案 4 :(得分:0)

我尝试使用Powershell通过COM启动Excel的实验:

$x = New-Object -com Excel.Application
$x.Visible = $True
Start-Sleep 5 # make it stay visible for a little while
$x.Quit()
$x = 0 # Remove .NET's reference to com object
[GC]::collect() # run garbage collection

一旦[GC] :: collect()完成,该过程就会从taskmgr中消失。这对我来说很有意义,因为(根据我的理解)COM客户端负责释放对COM服务器的引用。在这种情况下,.NET(通过运行时可调用包装器)是COM客户端。

IE的情况可能更复杂,因为可能存在与给定IE进程相关联的其他选项卡(并且@Noseratio提到的框架合并),但至少这将取消参考由PS脚本创建。

答案 5 :(得分:0)

这可能对您有用:

Get-Process | Where-Object {$_.Name -Match "iexplore"} | Stop-Process