Execute Code After Internet Explorer is Closed

by Lordmenta at 2012-11-09 03:52:22

Hi to all!

My first post! How cool!

Well…as the title suggest, i’m trying to execute code after Internet Explorer is closed.

I need to Disable the Internet Explorer proxy during the navigation, and re-enable it when the user has finished to navigate.

$regKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
Set-ItemProperty -Path $regKey -Name ProxyEnable -Value "0" #Disable Proxy
$ie = New-Object -ComObject InternetExplorer.Application
$ie.navigate('my.site.url')
$ie.visible = $true
# When the Internet Explorer window is closed execute the following code:
#Set-ItemProperty -Path $regKey -Name ProxyEnable -Value "1" #Enable Proxy


Many thanks for any suggestion!

Lordmenta
by DonJ at 2012-11-09 06:50:55
I’m not sure if you can detect that immediately. You’d need to look at the IE object model to see if it fires an event when it’s closing the last window. Alternately, you could probably do a Start-Sleep and check to see if the IExplore.exe process still exists every few seconds.
by Lordmenta at 2012-11-09 08:23:01
Hi Donj! Thanks for the reply…

I’ve googled about IE object model and i have found this about the event OnQuit

But i can’t find it in my Internet Exporer object created in PowerShell:

PS Repository:> $ie | Get-Member

TypeName: System.__ComObject#{d30c1661-cdaf-11d0-8a3e-00c04fc9e26e}

Name MemberType Definition
---- ---------- ----------
ClientToWindow Method void ClientToWindow (int, int)
ExecWB Method void ExecWB (OLECMDID, OLECMDEXECOPT, Variant, Variant)
GetProperty Method Variant GetProperty (string)
GoBack Method void GoBack ()
GoForward Method void GoForward ()
GoHome Method void GoHome ()
GoSearch Method void GoSearch ()
Navigate Method void Navigate (string, Variant, Variant, Variant, Variant)
Navigate2 Method void Navigate2 (Variant, Variant, Variant, Variant, Variant)
PutProperty Method void PutProperty (string, Variant)
QueryStatusWB Method OLECMDF QueryStatusWB (OLECMDID)
Quit Method void Quit ()
Refresh Method void Refresh ()
Refresh2 Method void Refresh2 (Variant)
ShowBrowserBar Method void ShowBrowserBar (Variant, Variant, Variant)
Stop Method void Stop ()
AddressBar Property bool AddressBar () {get} {set}
Application Property IDispatch Application () {get}
Busy Property bool Busy () {get}
Container Property IDispatch Container () {get}
Document Property IDispatch Document () {get}
FullName Property string FullName () {get}
FullScreen Property bool FullScreen () {get} {set}
Height Property int Height () {get} {set}
HWND Property int HWND () {get}
Left Property int Left () {get} {set}
LocationName Property string LocationName () {get}
LocationURL Property string LocationURL () {get}
MenuBar Property bool MenuBar () {get} {set}
Name Property string Name () {get}
Offline Property bool Offline () {get} {set}
Parent Property IDispatch Parent () {get}
Path Property string Path () {get}
ReadyState Property tagREADYSTATE ReadyState () {get}
RegisterAsBrowser Property bool RegisterAsBrowser () {get} {set}
RegisterAsDropTarget Property bool RegisterAsDropTarget () {get} {set}
Resizable Property bool Resizable () {get} {set}
Silent Property bool Silent () {get} {set}
StatusBar Property bool StatusBar () {get} {set}
StatusText Property string StatusText () {get} {set}
TheaterMode Property bool TheaterMode () {get} {set}
ToolBar Property int ToolBar () {get} {set}
Top Property int Top () {get} {set}
TopLevelContainer Property bool TopLevelContainer () {get}
Type Property string Type () {get}
Visible Property bool Visible () {get} {set}
Width Property int Width () {get} {set}

Maybe i’m not searching in the right place, or this event isn’t available for PowerShell-Invoked object?

Thanks again for the help!

Lordmenta
by DonJ at 2012-11-09 08:35:12
It would be an event. And it’s possible interop isn’t exposing it. Are you sure that’s not a DOM event?

Understand IE really wasn’t designed for this ;). Might be tricky or not possible.
by DonJ at 2012-11-09 12:25:31
Yeah, OnQuit isn’t an event of the IE object; it’s a DOM event that occurs to HTML elements. So no, that won’t work.

I’m guessing you’ll want to just look for the iexplore.exe process - and if that doesn’t show up when launching IE through the COM object, just launch IE using Start-Process. Enter a loop that runs Start-Sleep and periodically checks to see if IE is still running. Watch for the specific process ID returned by Start-Process, so that you’re not accidentally whacking any other IE instance.

The IE COM object just wasn’t made for that kind of close watching.
by MattG at 2012-11-09 16:16:17
Lordmenta,

Interesting problem with an interesting solution. I had fun with this one. Although the solution may not be entirely straightforward. Here’s the code to accomplish exactly what you want:
$regKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
Set-ItemProperty -Path $regKey -Name ProxyEnable -Value "0" #Disable Proxy
$ie = New-Object -ComObject InternetExplorer.Application
$ie.Navigate('my.site.url')
$ie.Visible = $True

# Compile a static P/Invoke interface to GetWindowThreadProcessId Win32 function
$Import = '[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId);'
Add-Type -MemberDefinition $Import -Name 'Process' -Namespace 'Custom' -PassThru | Out-Null

$ProcessId = 0
# Get the process ID of the IE COM object
[Custom.Process]::GetWindowThreadProcessId($ie.HWND, [ref] $ProcessId) | Out-Null
if ($ProcessId -eq 0) { Throw 'Could not get process ID of Internet Explorer!' }

$IEprocess = Get-Process -Id $ProcessId

$Action = { Set-ItemProperty -Path $regKey -Name ProxyEnable -Value "1"; Unregister-Event -SourceIdentifier ExitAction }

# Register an event listener for when IE exits. The event handler will unregister the event lister for you
Register-ObjectEvent -InputObject $IEprocess -EventName Exited -SourceIdentifier ExitAction -Action $Action

# Quit IE and $Action will fire. :smiley:
$ie.Quit()

What I’m doing here is getting the process ID of IE via the HWND parameter of the com object. Unfortunately, there is no processID parameter so the best way I could think of getting the PID was with the GetWindowThreadProcessId function in user32.dll. You could have just run ‘Get-Process iexplore’ but that would have returned multiple processes since each tab runs in its own process. You’d have to guess which one was the parent process.

I then register an event handler for the ‘Exited’ event in the IE System.Diagnostics.Process object. As soon as IE exits, $Action will fire and it will unregister the event handler.

Enjoy!
by DonJ at 2012-11-09 16:33:18
Wow, Matt.

I’m guessing that, if the script launched IE using Start-Process and had that specific ProcID to begin with, you could still register for that event without needing to go after the window handle, yeah?
by MattG at 2012-11-09 16:53:48
Yep. Exactly. That would be much easier.
by Makovec at 2012-11-10 04:31:09
Hi,

Just to summarize your thoughts for Lordmenta.$ie = Start-Process iexplore -PassThru
Register-ObjectEvent -InputObject $ie -EventName Exited -Action { $ActionSuggestedByMattG }
Then you can close IE whenever you need it and event will be fired (just for the specified process, not for any other possible). Maybe it’s also good idea to add Remove-Variable ie to Action otherwise you will have useless variable in your session.

David
by Lordmenta at 2012-11-12 01:01:36
Wow guys! Thanks a lot for the help! Now i will try to understand exactly the code and i will study what i don’t know…i’m new to PowerShell and i have a lot of things to understand!

During this time i have changed a little bit my approach to the problem…basically i havet ry to reach the solution with my small knowledge…here the code:

$regKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
Set-ItemProperty -Path $regKey -Name ProxyEnable -Value "0" #Disable Proxy
#Code for log the start time
$ie = New-Object -ComObject InternetExplorer.Application
$ie.navigate("my.site.url")
$ie.visible = $true
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show("When finished to use Internet click OK or close this windows", "WE ARE LOGGING YOUR TRAFFIC!")
Set-ItemProperty -Path $regKey -Name ProxyEnable -Value "1" #Enable Proxy
Get-Process iexplore | Foreach-Object { $_.CloseMainWindow() }
#Code for log the end time


I’ve "solved" the problem in a very dirty way…i’m launching my PS script with a VBS script…so the window will be "invisible to the user", he only will see the msgBox about the "logging traffic" disclaimer…when he close the msgBox the proxy is enabled again…and all the instance of IE opened without the proxy are closed.

Why i’m doing this?! We want our users navigate safely…when they are in the branch isn’t a problem, they are in an embedded-VPN environment…when they are at home or with a mobile connection isn’t a problem, we have a proxy enabled on 127.0.0.1 and if they want to navigate are forced to connect in VPN (so they use the company proxy)…the problem comes when they are try to connect in an airport or a hotel wifi…before having connecctivity (and log in VPN) they need to navigate on a "special" page and authenticate…and they can’t with my 127-proxy enabled.
This is why i want to put a shortcut on their desktop for enable the browsing in this special condition. The traffic will be controlled checking the domains visited in this time of the disabled proxy.

The user can "trick" the protecion killing the process powershell.exe with task manager, but my users are not so "technical" to do it…

Sorry for my long post but maybe can be helpful for someone!