locked
PowerShell script hangs on logout/shutdown RRS feed

  • Question

  • I wrote a PowerShell script which creates a notification icon which initially pops up a balloon tip intended to let Outlook Web Access users know if they have unread emails when they log in, then it stays in the notification tray so that they would have one-click access to OWA. Unfortunately if I log out or shut down while the script is running, I get an "End Program" dialog for PowerShell. I've tried a few different methods to detect that a shutdown is in progress and exit gracefully, such as having an invisible form or trying to add a handler for the PSEngineEvent.Exiting event, but nothing seems to help. Can anyone tell me how I can get the script to exit properly on logout or shutdown? Here is the script:

    #Requires -version 2
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    
    if ([System.Threading.Thread]::CurrentThread.ApartmentState -ne "STA") {
    	# wrong mode, reload powershell and then exit
    	& powershell -sta -WindowStyle Hidden -command .\owascraper.ps1
    	exit
    }
    
    # Use XmlHttp to grab OWA navbar
    $http = New-Object -com Microsoft.XmlHttp
    $http.open("GET","http://penfold/exchange/?Cmd=navbar", $false)
    $http.send()
    $s = $http.responseText
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($http)
    Remove-Variable http
    
    # Use IndexOf method to do InStr (fourth occurrence of /Inbox)
    $i = $s.IndexOf("/Inbox")
    $i = $s.IndexOf("/Inbox", $i + 1)
    $i = $s.IndexOf("/Inbox", $i + 1)
    $i = $s.IndexOf("/Inbox", $i + 1)
    # now find iCount
    $j = $s.IndexOf("iCount", $i) + 8
    # now find <
    $k = $s.IndexOf("<", $j)
    # Use SubString method to do Mid
    $m = [int] $s.SubString($j, $k - $j)
    
    $objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon 
    $objNotifyIcon.Icon = "\\COLL-APPS\Apps\Email Icon\longroadstamp.ico"
    $objNotifyIcon.Visible = $True
    $objNotifyIcon.add_Click({ & "$env:programfiles\Internet Explorer\iexplore.exe" 'http://penfold/exchange/' })
    
    if ($m -gt 0) {
    	# more than one unread email in inbox
    	$objNotifyIcon.BalloonTipIcon = "Info" 
    	$objNotifyIcon.BalloonTipText = "You have " + $m + " unread emails in your inbox." + [Environment]::NewLine + "Click this balloon to read your email."
    	$objNotifyIcon.BalloonTipTitle = "Long Road Email"
    
    	$objNotifyIcon.add_BalloonTipClicked({
    		& "$env:programfiles\Internet Explorer\iexplore.exe" 'http://penfold/exchange/'
    	})
    	$objNotifyIcon.ShowBalloonTip(30000)
    }
    
    [System.Windows.Forms.Application]::Run()
    
    $objNotifyIcon.Dispose()
    Get-Process -Name "powershell" | Stop-Process
    
    Monday, June 7, 2010 3:14 PM

Answers

  • Doing some more research, it looks like you can set up a Event watcher using Register-ObjectEvent using [microsoft.win32.systemevents] and watching for either SessionEnding or SessionEnded.  I haven't had time to test this out, but you could look at using something like this:

    Not Test:

    $sysevent = [microsoft.win32.systemevents]
    Register-ObjectEvent -InputObject $sysevent -EventName "SessionEnding" -Action {"Shutdown/Logoff detected.";Get-Process -Name Powershell | Stop-Process -Force}
    

    More information about this class can be found here:

    http://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents_events.aspx

    • Proposed as answer by Boe ProxMVP Wednesday, September 1, 2010 2:39 AM
    • Marked as answer by Boe ProxMVP Monday, September 6, 2010 9:49 PM
    Monday, August 30, 2010 3:33 AM

All replies

  • Are you still having problems with this script hanging during a log off?  Is this script run via a log on script and/or is this machine in a domain and managed by Group Policy?  One thing you might want to look at is using a logoff script to end the powershell process during the logoff which may avoid having the script hang.
    Saturday, August 28, 2010 12:16 AM
  • Doing some more research, it looks like you can set up a Event watcher using Register-ObjectEvent using [microsoft.win32.systemevents] and watching for either SessionEnding or SessionEnded.  I haven't had time to test this out, but you could look at using something like this:

    Not Test:

    $sysevent = [microsoft.win32.systemevents]
    Register-ObjectEvent -InputObject $sysevent -EventName "SessionEnding" -Action {"Shutdown/Logoff detected.";Get-Process -Name Powershell | Stop-Process -Force}
    

    More information about this class can be found here:

    http://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents_events.aspx

    • Proposed as answer by Boe ProxMVP Wednesday, September 1, 2010 2:39 AM
    • Marked as answer by Boe ProxMVP Monday, September 6, 2010 9:49 PM
    Monday, August 30, 2010 3:33 AM