Показывать всплывающие уведомления из командного файла

Я хотел бы показывать уведомления о всплывающих подсказках от партий, которые выполняются в течение длительного времени.

Я знаю, что вы можете показывать всплывающие окна (и некоторые решения очень оригинальны), но было бы интересно иметь эту опцию тоже.

Есть ли способ показать всплывающее уведомление из командного файла? По крайней мере, начиная с Windows 7, но XP тоже приветствуется.

Я полагаю, что потребуется хотя бы иконка в трее, но, честно говоря, я не могу идти дальше. Может быть с rundll32.exe? Я знаю, что это не рекомендуемый способ сделать что-либо из командной строки.

Подпись функции, необходимая для функций, вызываемых rundll32.exe, описана в этой статье базы знаний. Это не помешало людям использовать rundll32 для вызова случайных функций, которые не были предназначены для вызова rundll32, например user32 LockWorkStation или user32 ExitWindowsEx.

Но я нашел эту утилиту RunAnyDll от Yaniv Pessach, которая, кажется, делает правильные вызовы.dll. К сожалению, я не нашел работающей ссылки для проверки (нет, ее нет в интернет-архиве). Я написал автору, чтобы попросить его. Посмотрим.

(Я даже не знаю, будет ли это полезно, но это интересная утилита. Может быть, это поможет сработать в этом ответе на всплывающий вопрос. Я думаю, что разница между Run box и выполнение командной строки как-то связано с соглашением о вызовах в сообщении Рэймонда Чена.)

Еще одна необъяснимая утилита для тестирования - устаревшие триггеры событий, но, опять же, я не уверен, что это поможет.

Изменить, чтобы уточнить:

Ответы как npocmaka, так и greg zakharov очень интересны. Один из npocmaka ближе к тому, что я спрашивал, потому что он выдает всплывающее уведомление. Грег Захаров использует другую технику, но ее результат очень похож (в этом случае текст появляется в месте расположения указателя мыши). Я проверил их в 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 для каждого шарика кажется невыполнимым, если вы собираетесь использовать его несколько раз в пакете, поэтому, в конце концов, как утверждает Грег Захаров, более надежно и гибко генерировать только.exe-файл, который принимает параметры и повторно использует его (просто как уведомление). В конце концов, я предполагаю, что с помощью :balloon Подпрограмма, которая выполняет однострочный вызов PowerShell, - лучшее, что вы можете получить (почти изначально в XP, потому что вам нужна загрузка, но вам также нужен.net).

5 ответов

Решение

Использование PowerShell с одним вкладышем

Нет необходимости создавать файл, он работает независимо от политики выполнения. Спасибо Марку Додсонсу, который показал нам способ сделать это с помощью 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, но я не имел успеха до сих пор.

Вот скрипт полиглота jscript.net/bat (должен быть сохранен как .bat) с жестко закодированными значениями (код почти такой же, как в ссылке в моем комментарии), которая создаст простое уведомление в системном трее (будет работать на любой системе с установленным.NET. .NET устанавливается по умолчанию на каждом компьютере с Windows, начиная с Windows Vista так что это более обратно совместимо, чем 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

Methood 1: LC.exe CMDLet
Этот маленький CMDlet (переносимый.exe-файл, который можно вызвать из пакетного файла) может сравнивать два файла и строки экспорта, уникальные для первого файла в txt-документе с именем old.txt и строки, уникальные для второго в текстовом формате с именем new.txt контекст lc File1.txt File2.txt
Вот файл: http://1drv.ms/u/s!AlRLV33Rdz2CgrgeqSerXbeXyVhRYQ
Methood 2: скрипт 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 "Title" "Body" "Icon File"

Примечание. Для этого метода требуется, чтобы для политики выполнения Powershell было задано значение Unrestricted (не по умолчанию). Вы можете проверить это с этим:

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).

Существует множество хакерских методов для достижения поставленной цели. Один из них был описан 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)
));

Обратите внимание, что я не настоятельно рекомендую использовать гибриды и другие химеры. Я уверен, что лучший способ сделать то, о чем вы спрашиваете, - написать специальный инструмент командной строки.

Упрощенный из ответа @cdlvcdlv , он работает быстрее, если вызывается из другого файла.

уведомить.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');
Другие вопросы по тегам