让PS脚本等待NotifiyIcon点击,然后显示消息框并退出

时间:2015-09-15 18:41:23

标签: winforms powershell

我遇到一种情况,我需要一个计划任务来运行脚本,检查某些证书是否即将到期,然后通知用户。我选择使用Windows Forms NotifyIcon对象,因为我可以弹出一个看起来已集成到操作系统中的漂亮的小气球。我希望它在用户点击图标时显示一个MsgBox(好吧,我希望它在点击图标或气球时执行它,但是现在我会在图标上找到它)。

问题在于我无法让脚本等待用户点击图标,或者如果我设置循环以使脚本等待,我似乎无法让脚本退出用户单击图标时的循环。如果脚本只是退出而没有等待,则图标消失,带上气球,所以用户在屏幕上看到一个图标和气球闪光,并且在它们可以阅读或与之交互之前消失。这是一个展示问题的简化版本(您需要将图标路径更改为系统上的有效.ico文件)。

[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")|Out-Null

Function Show-MsgBox ($Text,$Title="",[Windows.Forms.MessageBoxButtons]$Button = "OK",[Windows.Forms.MessageBoxIcon]$Icon="Information"){
[Windows.Forms.MessageBox]::Show("$Text", "$Title", [Windows.Forms.MessageBoxButtons]::$Button, $Icon) | ?{(!($_ -eq "OK"))}
}

#Create Notification Icon
$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$objNotifyIcon.BalloonTipIcon = "Info"
$objNotifyIcon.BalloonTipText = "Click Me!"
$objNotifyIcon.BalloonTipTitle = "I'm a title"
$objNotifyIcon.Text = "Click Me!"
$objNotifyIcon.Icon = "C:\temp\vsmartcard.ico"

$NotDone = $true
$objNotifyIcon.add_click({Show-MsgBox -text "User Clicked Icon"; $Global:NotDone = $false})
$objNotifyIcon.Visible = $true
$objNotifyIcon.ShowBalloonTip(10000)
While($NotDone){
    "`$NotDone = $NotDone`nSleeping for 3 seconds"
    Start-Sleep -Seconds 3
}

$objNotifyIcon.Visible = $False
$objNotifyIcon.Dispose()

奇怪的是,如果我点源它,它会按预期工作,但如果我只运行脚本则不行。

我已尝试注册事件而不是使用add_click方法并使用Wait-Event cmdlet,但它从未注册事件发生,它或者永远坐在那里等待事件,如果我包括超时,它等待它过期,然后完成脚本并退出(在这种情况下,如果用户在超时的15秒内没有注意到它,可能永远不会看到我的通知)。我尝试过的代码如下(我在几年前Keith Hill的SO回答中找到的代码的修改版本):

Register-ObjectEvent $objNotifyIcon BalloonTipClicked -SourceIdentifier event_BalloonTipClicked -Action {
    Show-MsgBox -Text $Text -Title $Title
    Unregister-Event -SourceIdentifier $event.SourceIdentifier -Force
    Remove-Job $event.SourceIdentifier -Force
    $objNotifyIcon.Visible = $False
}
Register-ObjectEvent $objNotifyIcon Click -SourceIdentifier event_Click -Action {
    Show-MsgBox -Text $Text -Title $Title
    Unregister-Event -SourceIdentifier $event.SourceIdentifier -Force
    Remove-Job $event.SourceIdentifier -Force
    $objNotifyIcon.Visible = $False
}

$objNotifyIcon.Visible = $True
$objNotifyIcon.ShowBalloonTip(10000)
wait-event

我尝试在Break事件脚本块中包含ExitClick,但他们只是犯了错误。

1 个答案:

答案 0 :(得分:1)

while($Global:NotDone) { ... }

这样它就会引用事件中已经引用的相同变量。

结果证明不相关:

问题是没有什么可以等待这个事件,正如你所推测的那样。但是尝试添加循环将不起作用,因为你只有一个线程,现在它陷入沉睡和循环。

您可能需要为此使用事件,然后您需要等待事件,而不仅仅是睡觉。

我找到a good example of this on powershell.com

param 
( 
    $msg = "For the latest updates check our intranet website. Please click in the balloon.", 
    $title = "News", 
    $icon = "None", 
    $timeout=1 
) 

[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | out-null 
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | out-null 

$Balloon = new-object System.Windows.Forms.NotifyIcon  
$Balloon.Icon = [System.Drawing.SystemIcons]::Information 
$Balloon.Visible = $true; 
$Balloon.ShowBalloonTip($timeout, $title, $msg, $icon); 

Unregister-Event -SourceIdentifier click_event -ErrorAction SilentlyContinue 
Register-ObjectEvent $Balloon BalloonTipClicked -sourceIdentifier click_event -Action { 

$ie = New-Object -com InternetExplorer.Application 
$ie.navigate2("https://intranet.mydomain.com") 
$ie.visible = $true 

} | Out-Null 

Wait-Event -timeout 15 -sourceIdentifier click_event > $null 
Remove-Event click_event -ea SilentlyContinue 
Unregister-Event -SourceIdentifier click_event -ErrorAction SilentlyContinue 
$Balloon.Dispose() 

这里Wait-Event正在等待。

你说你有这种方法的问题。您是否可以将该代码编辑到问题中?