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,
This may be useful to you:
Get-Process | Where-Object {$_.Name -Match "iexplore"} | Stop-Process
With a quick look around in the ComObject for IE, it seems that when it is created, it gives you a direct interface to the methods that make interacting with IE easier, for example Navigate()
or ReadyState
.
I did discover a property that seems to be what you are looking for and that would be Parent
Calling $IE.Parent.Quit()
seemed to get rid of the PowerShell created instances.
$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...
I tried an experiment with Powershell launching Excel via COM:
$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
As soon as [GC]::collect() finished the process disappeared from taskmgr. This makes sense to me, because (in my understanding) a COM client is responsible for releasing references to the COM server. In this case .NET (via a Runtime Callable Wrapper) is the COM client.
The situation may be more complicated with IE, since there may be other tabs associated with a given IE process (and there's the frame merging that @Noseratio mentions), but at least this will get rid of the reference created by the PS script .
There's HKCU\Software\Microsoft\Internet Explorer\Main\FrameMerging
registry key that prevents merging IE "frame" processes, explained here. I haven't tried it myself, but I think it might solve your problem if you set it before you instantiate the InternetExplorer.Application
COM object.
If that doesn't help, try launching a new IE instance with the following command line, prior to creating the COM object (I haven't tried that, either):
iexplore.exe -noframemerging -private -embedding
There is a possible race condition before this IE instance becomes available as a COM server, so you may want to put some delay before you create an object.
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()
I've had similar problems with COM objects that wouldn't terminate using the quit() method. Interopservices.marshall also doesn't work a lot of times. My workaround : I do a get-process to get a list of all procs before I call the com object and right after : this way I have the PID of my instance. After my script runs it kills the process using stop-process.
Not the best way to do this but at least it works