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つのタブが常に開いています。
_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()
_
COMオブジェクトで、quit()メソッドを使用しても終了しない同様の問題がありました。 Interopservices.marshallもあまり機能しません。私の回避策:comオブジェクトを呼び出す前にget-processを実行してすべてのプロシージャのリストを取得し、直後に:このようにしてインスタンスのPIDを取得します。スクリプトを実行した後、stop-processを使用してプロセスを強制終了します。
これを行うための最良の方法ではありませんが、少なくともそれは機能します
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スクリプトによって作成された参照。
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...
マージを防止するHKCU\Software\Microsoft\Internet Explorer\Main\FrameMerging
レジストリキーがありますIE "frame" processes、 ここで説明 。私自身は試していませんが、解決できると思いますbeforeに設定した場合の問題は、InternetExplorer.Application
COMオブジェクトをインスタンス化することです。
それでも問題が解決しない場合は、新しいIEインスタンスを次のコマンドラインで起動してみてください。prior COMオブジェクト(私も試していません):
iexplore.exe -noframemerging -private -embedding
このIEインスタンスがCOMサーバーとして利用可能になる前に、競合状態が発生する可能性があります。そのため、オブジェクトを作成する前に遅延を設定することをお勧めします。
これはあなたに役立つかもしれません:
Get-Process | Where-Object {$_.Name -Match "iexplore"} | Stop-Process