开发者

PowerShell script to display Notification balloon and take action only works in ISE gui, not from commandline

I've seen a bunch of closely related posts so I know i'm not alone, but none have given me the answer I'm looking for. Apologies if this has been asked and answered and I couldn't find it.

this script creates a custom notification area balloon, which, if clicked on is meant to open a new IE window to some URL. Works great from the PowerShell ISE GUI that I've been working with it in. Can't get it to work from command-line using any of the options i've seen suggested in other posts. Specifically, can't get the IE window to open. The notification appears no problem, but no IE window...?? Tried with:

  • powershell . script.ps1
  • powershell -file script.ps1
  • command
  • &

etc.

Thoughts?

My script:

#Load the required assemblies
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)
#Remove any registered events related to notifications
Remove-Event BalloonClicked_event -ea SilentlyContinue
Unre开发者_开发百科gister-Event -SourceIdentifier BalloonClicked_event -ea silentlycontinue
Remove-Event BalloonClosed_event -ea SilentlyContinue
Unregister-Event -SourceIdentifier BalloonClosed_event -ea silentlycontinue
Remove-Event Disposed -ea SilentlyContinue
Unregister-Event -SourceIdentifier Disposed -ea silentlycontinue

#Create the notification object
$notification = New-Object System.Windows.Forms.NotifyIcon 
#Define various parts of the notification
$notification.Icon = [System.Drawing.SystemIcons]::Information
$notification.BalloonTipTitle = “**Reminder**”
$notification.BalloonTipIcon = “Warning”
$title = “message to user”
$notification.BalloonTipText = $title

#Make balloon tip visible when called
$notification.Visible = $True

## Register a click event with action to take based on event
#Balloon message clicked
register-objectevent $notification BalloonTipClicked BalloonClicked_event -Action {
    Start-Process 'c:\Program Files\Internet Explorer\iexplore.exe' -ArgumentList 'http://someURL.com' -WindowStyle Maximized -Verb Open
    #Get rid of the icon after action is taken
    $notification.Dispose()
    } | Out-Null

#Balloon message closed
register-objectevent $notification BalloonTipClosed BalloonClosed_event -Action {$notification.Dispose()} | Out-Null

#Call the balloon notification
$notification.ShowBalloonTip(1000)


The reason why it doesn't work in non-interactive prompts is that powershell has already finished processing when the user clicks the balloon.

You can fix that in one of two ways:

  • add a sleep(1) at the end of the script, so it doesn't end before the user clicking the balloon; (increase the value if needed, although I tested w/ 1 sec just fine)
  • use the -noexit commandline parameter and then close powershell programatically upon the user clicking the notification or after some delay (I tested that it would launch IE with no changes to your code, didn't bother coding the exit part.)


Changed to C# with help from a real developer. Would appreciate a true powershell answer though if anyone has it.

New code:

$code = @'
using System;
using System.Drawing;
using System.Windows.Forms;

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        NotifyIcon nicon = new NotifyIcon();
        nicon.BalloonTipIcon = ToolTipIcon.Info;
        nicon.BalloonTipText = "message to user";
        nicon.BalloonTipTitle = "*** title for user ***";
        nicon.Icon = SystemIcons.Information;
        nicon.BalloonTipClicked += (sender, e) =>
        {
            System.Diagnostics.Process.Start("http://website.com");
            CleanUp(nicon);
        };
        nicon.BalloonTipClosed += (sender, e) => CleanUp(nicon);
        nicon.Visible = true;
        nicon.ShowBalloonTip(1000 * 1);
        Application.Run();
    }
    static void CleanUp(NotifyIcon c)
    {
        c.Visible = false;
        c.Dispose();
        Application.Exit();
    }
}

'@
Write-Host $code
Add-Type -OutputType WindowsApplication -OutputAssembly c:\temp\test.exe -TypeDefinition  $code -ReferencedAssemblies "System.Drawing","System.Windows.Forms" -Language CSharpVersion3


I believe the solution is to start PowerShell.exe (ie. console window) with the -sta parameter.

Windows GUI code needs to run in a thread set as a COM "Single Threaded Apartment" (STA), but by default the worker thread in a PowerShell console is running in a "Multi Threaded Apartment" (MTA).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜