从批处理文件中显示气球通知

9
我希望能够在长时间运行的批处理中显示气球通知。
我知道你可以显示弹出窗口(有些解决方案非常富有想象力),但也很有趣能够拥有这个选项。
是否有一种方法可以从批处理文件中显示气球通知?请至少从Windows 7开始,但XP也欢迎。
我想这至少需要一个托盘图标,但坦率地说,我不能走得更远了。也许可以用rundll32.exe?我知道这不是从命令行执行任何操作的推荐方式
这篇知识库文章记录了rundll32.exe调用函数所需的函数签名。但是,这并没有阻止人们使用rundll32来调用未设计为被rundll32调用的随机函数,例如user32 LockWorkStation或user32 ExitWindowsEx。但我发现Yaniv PessachRunAnyDll实用程序似乎可以正确地进行.dll调用。不幸的是,我找不到一个可行的链接来测试它(不,它不在互联网档案馆中)。我已经写信给作者请求一个链接。让我们看看吧。

(我甚至不知道它是否有用,但它是一个有趣的实用工具。也许它可以使this answer对弹出问题起作用。我认为Run框和命令行执行之间的区别与雷蒙德·陈文章中的调用约定有关。)

另一个无法找到的实用程序是已弃用的eventtriggers,但我也不确定它是否有帮助。

编辑以澄清:

npocmakagreg zakharov的答案都非常有趣。npocmaka的答案更接近我的问题,因为它产生了一个气球通知。greg zakharov使用了一种不同的技术,但其结果非常相似(在这种情况下,文本出现在鼠标指针位置)。我已经在XP中测试过它们,两者都有效(需要安装.NET)。两者都有超时,我不知道如何保持通知直到用户点击(以防用户不在但您想看到它)。

理想情况下,我的问题是如何获得类似这样的东西。
@echo off

echo Some long part job that goes well.

call :balloon "Report about above tasks" [optional parameters about icon, title, timeout, etc.]

echo More tasks but one fails
if errorlevel 1 call :balloon "Error this and that" [optional parameters]

echo This is the end of the tasks
goto :eof

:balloon

    echo If you don't want to make a temporary file
    echo then you must make one-liner calls to PowerShell, wscript or whatever.

exit /b

因此,作为混合脚本,我看到的缺点是将其插入到任何批处理中可能非常困难。为每个气球生成一个 .exe 似乎是不切实际的,特别是如果你要在批处理中多次重复使用它们,因此,正如greg zakharov所说,更健壮和灵活的方法是生成一个只接受参数并可重复使用的 .exe 文件(就像notifu一样)。最终,我认为使用一个:balloon子例程来进行一行式的PowerShell调用可能是你能得到的最好的结果(在XP中几乎原生,但是你需要下载,也需要 .net)。


通过气球通知,您是指来自系统托盘的消息吗?我发现链接到微软文章的页面已经不存在了。不过您唯一的选择是通过.NET使用平台调用,这意味着需要使用C#/VB.NET/JScript.NET/powershell,它们可以嵌入批处理中。也许在这里 - https://www.pinvoke.net/ - 您可以找到所需的示例。 - npocmaka
1
看起来 .net api 直接调用系统托盘 - https://dev59.com/YWYr5IYBdhLWcg3w0tWE - npocmaka
你尝试过使用PowerShell吗?我可以给你我的脚本,但需要更改一些安全设置。如果你有兴趣,我还有一个cmdlet。 - Mark Deven
1
我不懂PowerShell(甚至不确定什么是cmdlet),而且由于默认安全设置,我也不太喜欢它,这使得在任何系统中使用它都很困难,但这并不重要。也许我会用它,但即使我不用,你也应该提供你的解决方案,以防其他人寻找方法来做这件事可以使用它。所以,如果你的答案相关,请欢迎回答。 - cdlvcdlv
我不确定这个 cmdlet 如何与智能屏幕配合工作,因为它只是一个没有公司制作的小脚本,但你不需要管理员访问权限或任何不同的安全设置来运行该部分。 - Mark Deven
显示剩余2条评论
5个回答

15

使用 PowerShell 一行命令

无需创建文件,它可以在任何执行策略下工作。感谢 Mark Dodsons 向我们展示了使用 PS 进行操作的方法,以及npocmaka提供的图标列表。

保存为,例如,balloon.bat(当然,您可以将其作为任何批处理程序中的子程序插入)。

@echo off

if "%~1"=="" call :printhelp  & exit /b 1
setlocal

if "%~2"=="" (set Icon=Information) else (set Icon=%2)
powershell -Command "[void] [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); $objNotifyIcon=New-Object System.Windows.Forms.NotifyIcon; $objNotifyIcon.BalloonTipText='%~1'; $objNotifyIcon.Icon=[system.drawing.systemicons]::%Icon%; $objNotifyIcon.BalloonTipTitle='%~3'; $objNotifyIcon.BalloonTipIcon='None'; $objNotifyIcon.Visible=$True; $objNotifyIcon.ShowBalloonTip(5000);"

endlocal
goto :eof

:printhelp
echo USAGE: %~n0 Text [Icon [Title]]
echo Icon can be: Application, Asterisk, Error, Exclamation, Hand, Information, Question, Shield, Warning or WinLogo
exit /b

如果没有第二个参数,它会默认为“Information”。 我想你可以使用mshta和vbscript或javascript,但是到目前为止我还没有成功。

非常好!是否可以扩展通知功能,例如在通知被点击时添加一个操作?(或者更好的是,在通知中添加一个可交互的按钮?) - ETL

8
以下是一个 jscript.net/bat 多语言脚本(必须保存为 .bat),其中包含硬编码值(代码与我评论中的链接几乎相同),它将创建一个简单的系统托盘通知(适用于安装了 .NET 的每个系统。自 Windows Vista 以来,.NET 已默认安装在每台 Windows 计算机上,因此比 powershell 更具向后兼容性):
@if (@X)==(@Y) @end /* JScript comment
@echo off

setlocal
del /q /f %~n0.exe >nul 2>&1
for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
   set "jsc=%%v"
)

if not exist "%~n0.exe" (
    "%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
)

if exist "%~n0.exe" ( 
    "%~n0.exe" %* 
)


endlocal & exit /b %errorlevel%

end of jscript comment*/

import System;
import System.Windows;
import System.Windows.Forms;
import System.Drawing;
import System.Drawing.SystemIcons;

var notification;
try {
    notification = new System.Windows.Forms.NotifyIcon();


} catch (err){

}

notification.Icon = System.Drawing.SystemIcons.Hand; // Could be Application,Asterisk,Error,Exclamation,Hand,Information,Question,Shield,Warning,WinLogo
notification.BalloonTipText = "Message!!";
notification.Visible = true;
// optional - BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info;
// optional - BalloonTipTitle = "My Title",




// Display for 2 seconds.
notification.ShowBalloonTip(2000);
System.Threading.Thread.Sleep(2100);

notification.Dispose();

它会编译一个小的可执行文件,然后调用它。如果不想创建临时可执行文件,可以查看使用了msbuild技术的这里(但这只适用于Windows 10)。我还可以创建一个参数化版本。
编辑:这里有一个工具,带有命令行选项:
call systemTrayNotification.bat   -tooltip warning -time 3000 -title "Woow" -text "Boom" -icon question

4

方法一: LC.exe CMDlet
这个小CMDlet(一个可从批处理文件内部调用的便携式.exe文件)可以比较两个文件,并将第一个文件中独特的行导出到名为old.txt的文本文档中,将第二个文件中独特的行导出到名为new.txt的文本文档中,语法为lc File1.txt File2.txt
这是文件:1drv.ms/u/s!AlRLV33Rdz2CgrgeqSerXbeXyVhRYQ
方法二: 批处理文件中的Powershell脚本

:notification
::Synax is call :notification [Title] [Body] [Icon]
echo notification: %1 %2 %3

echo [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") > notfy.ps1
echo $objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon  >> notfy.ps1
echo $objNotifyIcon.Icon = "ico%3.ico" >> notfy.ps1
echo $objNotifyIcon.BalloonTipIcon = "None"  >> notfy.ps1
echo $objNotifyIcon.BalloonTipText = %2  >> notfy.ps1
echo $objNotifyIcon.BalloonTipTitle = %1 >> notfy.ps1
echo $objNotifyIcon.Visible = $True  >> notfy.ps1
echo $objNotifyIcon.ShowBalloonTip(10000) >> notfy.ps1

Powershell "& ""%cd%\notfy.ps1"""
del /f /q "notfy.ps1"
exit /b

只需将此内容添加到批处理文件中,并使用call :notification "标题" "正文" "图标文件"调用它。



注意: 此方法需要将PowerShell执行策略设置为无限制(不是默认设置)。您可以使用以下命令测试此设置:

powershell Get-ExecutionPolicy >pgep.t
Find "Unrestricted" "pgep.t" >nul
if %errorlevel%==0 goto setuphere
del /f /q pgep.t
:setuphere
::Start a Batch File as admin with the command [Powershell Set-ExecutionPolicy $POLICY -Force] in it. (remove the brackets).

该程序的名称是 notification.exe,但是你的解释对我来说毫无意义。我以为你会添加一些 PowerShell 代码,以便读者可以了解你是如何做到的,并使用或扩展它。 - cdlvcdlv
我没有测试过,但理论上你可以用 powershell.exe -executionpolicy bypass -windowstyle hidden -noninteractive -nologo -file "notify.ps1" 替换 Powershell "& ""%cd%\notfy.ps1"""。然而,我认为这需要批处理文件以管理员身份运行。 - Mark Deven
你看,这就是为什么我不喜欢使用.ps1文件的原因:首先,如果可能的话,我会避免创建任何文件。更不用说一个固定的名称了,以防批处理文件的并发实例正在使用这种技术--目标是一种通用的方式(即可重用)来让.bat文件显示气球弹出窗口,如果你在运行时创建/删除文件,你会期望发生冲突。... - cdlvcdlv
此外,如果执行策略是默认的(最有可能的情况),它将失败或者需要管理员权限来更改策略并恢复它...只是为了显示一个该死的气球。你最终感觉像是用大锤去击碎一个坚果。但是谢谢(+1)你展示如何制作它。我想我会尝试使用单行代码避免执行策略。 - cdlvcdlv

3

有很多hacky方法可以实现所述目标。其中一个被npocmaka描述过。请注意,相同的方法也可以用于PowerShell(如何组合PowerShell脚本的示例可以在这里找到)。另一个可能会引发思维的怪物(这个可以与WinXP兼容)是CMD加WSH。

0</* :
@echo off
  setlocal
    echo Some batch code here...
    cscript /nologo /e:jscript "%~f0" "Warning!"
    pause
    echo Another batch code...
    cscript /nologo /e:jscript "%~f0" "All done!"
    pause
  endlocal
exit /b*/0;
(function(msg) {
   with (new ActiveXObject('Internet.HHCtrl')) {
      TextPopup(msg, 'Lucida Console, 23', 1, 1, 1, 1);
      WScript.Sleep(1500);
   }
}(
   WScript.Arguments.length !== 1 ?
   WScript.Quit(1) : WScript.Arguments.Unnamed(0)
));

请注意,我并不强烈推荐使用混合系统和其他类似的技术。我相信最好的方法是编写特殊的命令行工具来完成您所需的操作。

1

从 @cdlvcdlv answer 简化而来,如果从不同的文件中调用,则运行速度更快。

notify.bat

@echo off
if "%~3"=="" (set Icon=Information) else (set Icon=%3)
cmd /c powershell -WindowStyle Hidden -Command "[void] [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); $global:balloon = New-Object System.Windows.Forms.NotifyIcon; $balloon.Icon = [system.drawing.systemicons]::%Icon%; $balloon.Visible = $true; $balloon.ShowBalloonTip(5000, '%1', '%2', 'None'); Timeout /NoBreak 5; $balloon.Dispose(); Exit;"
EXIT 0

现在可以这样调用:

// Synthax
notify.bat "Title" "Message" "Type"

// Example 1
notify.bat "MyScript - Warning" "Some files are missing" "Warning"

// Example 2
cmd /c notify.bat "MyScript - Success" "Client is running"

如果你注意到了,所有的这些

$balloon.BalloonTipIcon = 'Icon'
$balloon.BalloonTipText = 'Text'
$balloon.BalloonTipTitle = 'Title'

我们将简化为这样

$balloon.ShowBalloonTip(5000, 'Title', 'Text', 'Icon');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接