web-dev-qa-db-ja.com

PowerShellから起動したときにInternet Explorerを適切に閉じる方法は?

PowerShellを介してInternet Explorerで何かを行うことについて、最近寄せられた一連の質問がありました。それらのすべてには、_$ie=new-object -comobject InternetExplorer.Application_を介してオブジェクトとしてPowerShellからIEを起動するためのコードが含まれています。問題は、を閉じる適切な方法ですIE $ie.quit()の呼び出しからなる機能は動作しません-最初に、IEが発生した場合IEは全体として終了せず、COMオブジェクトに対応するタブのみが閉じられます。次に、タブが1つしかない場合はウィンドウ閉じられますが、プロセスは残ります。

_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_で開始されたプロセスを閉じる方法についてメソッドを調べてみましたが、次のことがわかりました: COMObjectを取り除く方法 。そのCOMObjectの例は_Excel.Application_です。これは実際に意図したとおりに動作します-quit()を呼び出すとウィンドウが閉じ、_$ex_が作成された場合は[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ex)を実行します。 Excelプロセス。しかし、これはInternet Explorerには当てはまりません。

私もこの質問を見つけました: 実行中のIEの既存のCOMオブジェクトを取得する方法 これは、IEに開いているウィンドウのリストを介して接続するコードを提供し、 IEの範囲は他の場所から起動されますが、PowerShellを介してCOMオブジェクトが作成された場合、このように変更された場合、このスクリプトは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内で起動した場合、2つのプロセスが残り、このコードはCOMオブジェクトに到達するためのIEウィンドウが見つからないため、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起動時に「ホームページを開く」に設定されているため、少なくとも1つのタブが常に開いています。

8
Vesper

_iexplore.exe_を実行して作成されたか、PowerShellでCOMオブジェクトをインスタンス化して作成されたかに関係なく、Quit()メソッドを呼び出すだけで、通常はInternet Explorerプロセスを正常に終了できます。

デモンストレーション:

 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'}
 
 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()
_
9
Ansgar Wiechers

COMオブジェクトで、quit()メソッドを使用しても終了しない同様の問題がありました。 Interopservices.marshallもあまり機能しません。私の回避策:comオブジェクトを呼び出す前にget-processを実行してすべてのプロシージャのリストを取得し、直後に:このようにしてインスタンスのPIDを取得します。スクリプトを実行した後、stop-processを使用してプロセスを強制終了します。

これを行うための最良の方法ではありませんが、少なくともそれは機能します

2
bluuf

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プロセスに関連付けられた他のタブがある(そして@Noseratioが言及しているフレームのマージがある)ので、状況はIEでより複雑になるかもしれませんが、少なくともこれは取り除かれますPSスクリプトによって作成された参照。

1
Χpẘ

ComObject for IEをざっと見てみると、作成されたときに、IEとのやり取りを簡単にするメソッドへの直接インターフェイスが提供されているようです。たとえば、Navigate()またはReadyState

私はあなたが探しているものと思われるプロパティを発見しました、それはParentでしょう

$IE.Parent.Quit()を呼び出すと、PowerShellで作成されたインスタンスが削除されたようです。

$IE = New-Object -ComObject InternetExplorer.Application
Get-Process | Where-Object {$_.Name -Match "iex"}

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    291      20     5464      14156   200     0.16   1320 iexplore
    390      30     5804      20628   163     0.14   5704 iexplore

$IE.Parent.Quit()
(Get-Process | Where-Object {$_.Name -Match "iex"}).GetType()
You cannot call a method on a null-valued expression...
1
SomeShinyObject

マージを防止するHKCU\Software\Microsoft\Internet Explorer\Main\FrameMergingレジストリキーがありますIE "frame" processes、 ここで説明 。私自身は試していませんが、解決できると思いますbeforeに設定した場合の問題は、InternetExplorer.Application COMオブジェクトをインスタンス化することです。

それでも問題が解決しない場合は、新しいIEインスタンスを次のコマンドラインで起動してみてください。prior COMオブジェクト(私も試していません):

  • iexplore.exe -noframemerging -private -embedding

このIEインスタンスがCOMサーバーとして利用可能になる前に、競合状態が発生する可能性があります。そのため、オブジェクトを作成する前に遅延を設定することをお勧めします。

0
noseratio

これはあなたに役立つかもしれません:

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