从 PowerShell 启动时如何正确关闭 Internet Explorer? [英] How to properly close Internet Explorer when launched from PowerShell?

查看:28
本文介绍了从 PowerShell 启动时如何正确关闭 Internet Explorer?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近有一组关于通过 PowerShell 使用 Internet Explorer 进行操作的问题.它们都包含通过 $ie=new-object -comobject InternetExplorer.Application 从 PowerShell 作为对象启动 IE 的代码.问题是,由调用 $ie.quit() 组成的 关闭 IE 的正确方法不起作用 - 首先,如果该 IE 碰巧有超过单个打开的选项卡,IE 不会整体退出,只关闭与 COM 对象对应的选项卡,其次,如果它只有一个选项卡,则窗口会关闭,但进程会保留.

PS >获取进程 iexplore处理 NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName------- ------ ----- ----- ----- ------ -- -----------352 31 7724 24968 142 0,58 3236228 24 22800 15384 156 0,19 3432

我试图研究如何关闭通过 New-Object -ComObject 启动的进程的方法,并发现:如何摆脱 COMObject.该 COMObject 的示例是 Excel.Application,它的行为确实符合预期 - 调用 quit() 使窗口关闭,并执行 [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ex) 如果 $ex 是已创建的 COMObject,则停止 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)}}

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

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

环境:操作系统 Windows 7 x64,PowerShell 4(安装在 PS 版本 2 以上),IE11 版本 11.0.9600.17691(自动更新).IE 在启动时设置为打开主页",因此至少有一个标签始终处于打开状态.

解决方案

通常只需调用 Quit() 方法即可正常终止 Internet Explorer 进程,无论它们是否是通过运行 iexplore.exe 或通过在 PowerShell 中实例化 COM 对象.

演示:

<上一页>PS C:> $env:PROCESSOR_ARCHITECTUREAMD64PS C:> (Get-WmiObject -Class Win32_OperatingSystem).Caption微软视窗 8.1 企业版PS C:> 获取进程 |?{ $_.ProcessName -eq 'iexplore' }PS C:> $ie = New-Object -COM 'InternetExplorer.Application'PS C:> 获取进程 |?{ $_.ProcessName -eq 'iexplore' }处理 NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName------- ------ ----- ----- ----- ------ -- -----------352 20 4244 14164 176 0.05 3460 探索407 32 6428 23316 182 0.23 5356PS C:> $ie.Quit()PS C:> 获取进程 |?{ $_.ProcessName -eq 'iexplore' }PS C:>_

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

(New-Object -COM 'Shell.Application').Windows() |Where-对象{$_.Name -like '*Internet Explorer*'} |ForEach-对象 {$_.Quit()}

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

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

There was a set of recently asked questions about doing something with Internet Explorer via PowerShell. All of them contain codes to launch IE from PowerShell as an object, via $ie=new-object -comobject InternetExplorer.Application. The problem is, the proper way of closing IE that consists of calling $ie.quit() does not work - first, if that IE would have happened to have more than a single open tab, IE doesn't quit as a whole and only the tab that corresponds to the COM object is closed, and second, should it have only one tab, the window gets closed but the processes remain.

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

I have tried to research the methods on how to close a process started via New-Object -ComObject, and have found this: How to get rid of a COMObject. The example of that COMObject is Excel.Application, which indeed behaves as intended - calling quit() makes window close, and executing [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ex) if $ex is a created COMObject stops the Excel process. But this is not the case with Internet Explorer.

I have also found this question: How to get existing COM Object of a running IE which provides code to connect to IE via list of open windows, and works to an extent of IE launched from elsewhere, but if the COM object is created via PowerShell, this script is not able to completely stop IE's processes, if modified as such:

$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)
  }
}

In case of IE launched outside of PowerShell, the processes are stopped, but in case of IE launched within PowerShell, two processes remain, and this code reports to have found no IE windows to reach COM objects, therefore IE processes are (yet) unable to be stopped.

So, how to reach the apparently orphaned windowless IE processes and gracefully stop them? I am aware of Get-Process iexplore | Stop-Process, but this will stop any and all IEs, not just those launched by the script, and if the script is run as administrator or SYSTEM on a, say, remote desktop server, everyone's IEs will be stopped.

Environment: OS Windows 7 x64, PowerShell 4 (installed above PS version 2), IE11 version 11.0.9600.17691 (automatically updated). IE set to "Open home page" upon starting, so at least one tab is always open.

解决方案

Simply calling the Quit() method should normally suffice for gracefully terminating Internet Explorer processes, regardless of whether they were created by running iexplore.exe or by instantiating a COM object in PowerShell.

Demonstration:

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:> _

If you have orphaned Internet Explorer processes to which you don't have a handle you can cycle through them like this:

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

To be totally on the safe side you can release the COM object after calling Quit() and then wait for the garbage collector to clean up:

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

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

这篇关于从 PowerShell 启动时如何正确关闭 Internet Explorer?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆