Show balloon notifications from batch file

11,425

Solution 1

Using a PowerShell one-liner

No need to create a file, it works no matter what execution policy is. Thanks to Mark Dodsons that showed us the way to do this with PS and to npocmaka for the icons list.

Save as, for example, balloon.bat (of course, you can insert this as subroutine in any batch).

@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

If there's no second parameter it defaults to Information.

I suppose you can use mshta and vbscript or javascript, but I had no success until now.

Solution 2

Here's a jscript.net/bat polyglot script (must be saved as .bat) with hardcoded values (code is almost the same as in the link in my comment) that will create a simple system tray notification (will work on every system with installed .NET. .NET is installed by default on every windows machine since Windows Vista so this is more backward compatible than 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();

It will compile a small executable that will be called. If you don't want to create a temporary executables you can check the msbuild technique used here (though this will work only on windows 10). I can create also a parametrized version of this.

EDIT: here's a tool with a command line options:

call systemTrayNotification.bat   -tooltip warning -time 3000 -title "Woow" -text "Boom" -icon question

Solution 3

Methood 1: LC.exe CMDLet
This little CMDlet (A Portable .exe file you can call from within a batch file) can compare two files and export lines unique to the first file in a txt doc named old.txt and lines unique to the second in a txt named new.txt the context is lc File1.txt File2.txt
Here is the file: 1drv.ms/u/s!AlRLV33Rdz2CgrgeqSerXbeXyVhRYQ
Methood 2: Powershell Script in Batch File

: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

Simply add that to your batch file and call it with call :notification "Title" "Body" "Icon File"

Note: This methood requires The Powershell Execution Policy to be set to Unrestricted (not a default setting). You can test this with this:

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).
Share:
11,425

Related videos on Youtube

cdlvcdlv
Author by

cdlvcdlv

Updated on July 18, 2022

Comments

  • cdlvcdlv
    cdlvcdlv almost 2 years

    I would like to show balloon notifications from batches that run during long time.

    I know you can show popups (and some solutions are very imaginative), but it would be interesting to have this option too.

    Is there a way you can show a balloon notification from a batch file? Starting from Windows 7 at least please but XP welcome too.

    I suppose it would necessary at least a tray icon but frankly I cannot go much farther. Maybe with rundll32.exe? I know this is not a recommended way to do anything from command line.

    The function signature required for functions called by rundll32.exe is documented in this Knowledge Base article. That hasn't stopped people from using rundll32 to call random functions that weren't designed to be called by rundll32, like user32 LockWorkStation or user32 ExitWindowsEx.

    But I found this RunAnyDll utility by Yaniv Pessach that appears to make the .dll calls right. Unfortunately, I found not a working link to test it (no, it isn't in the Internet archive). I've written the author to ask him for one. Let's see.

    (I don't even know if it will be useful but it's an interesting utility. Maybe it could make work this answer to the popup question. I think the difference between the Run box and the command line execution has something to do with the calling convention thing in Raymond Chen post.)

    Another unfindable utility to test is the deprecated eventtriggers but again I'm not sure if it would be of help.

    Edit to clarify:

    Both npocmaka and greg zakharov answers are very interesting. npocmaka's one is nearer to what I was asking because it produces a balloon notification. greg zakharov's uses a diferent technique but its outcome is very similar (in this case a text appearing at mouse pointer location). I've tested them in XP and both work (with .NET installed). Both have a timeout and I don't know how to keep the notification until the user clicks (just in case the user is out but you want to see it).

    Ideally, my question was about getting something like this.

    @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
    

    So being hybrid scripts the drawback I see is that it must be very difficult to insert this inside any batch. Generating an .exe for every balloon seems impracticable if you are going to reuse several times in your batch so, in the end, as greg zakharov states, it's more robust and flexible to generate just an .exe that accept parameters and reuse it (just as notifu). In the end, I suppose that using a :balloon subroutine that makes a one-liner powershell call is the best you can get (almost natively in XP because you need a download but you also need .net).

    • npocmaka
      npocmaka almost 6 years
      Looks like .net api has direct calls to the system tray - stackoverflow.com/questions/13373060/…
    • cdlvcdlv
      cdlvcdlv almost 6 years
      I don't know powershell (I'm not even sure of what a cmdlet is) and I am not very fond of it because of default security settings, that makes difficult use it in any system, but that doesn't matter. Maybe I use it, but even if I don't you should as well give your solution just in case some other people looking for a way to do this can use it. So, please, if your answer is relevant is welcome.