I’ve deployed Ninite Pro to update non-Windows applications on computers that I manage. I’m running it in silent mode but I wanted some decent logging so I can review what it did. This is especially useful when run from the SolarWindows RMM dashboard as a Scheduled Task: the output is visible from the dashboard.
The script takes two parameters:
Param 1 Path to local or network copy of NiniteOne.exe.
Param 2 Optional path to a NiniteDownloads cache. This can be on a network share, in which case the MAXfocus agent must run as a user with network access (not as the default SYSTEM account). Defaults to %temp%\NiniteDownloads
if not specified. Fails if not accessible.
Example (type on one line):
NiniteUpdate.cmd "%SystemDrive%\Scripts\Helpers" "\\SRV01\NiniteDownloads"
Behavior
Ninite is run three times: first in /audit
mode, then in /updateonly
mode, then again in /audit
mode. Output is written to the NiniteUpdateSummary.log
file in the same folder as the script. “Not installed” messages are omitted, so you get a nice summary of what is installed. When the script completes, the NiniteUpdateSummary.log
file is written to stdout (which is what is displayed in the MAXfocus dashboard). Additionally, the full result of the final audit (including the “Not installed” messages) is saved as NiniteAuditAfterUpdate.log
.
There is a hard-coded variable in the script called CommonParams that excludes Microsoft programs (I use Microsoft Update for those), some other programs that were not updating, and TeamViewer (since that update can clobber the RMM Take Control function). I also set it to /disableshortcuts. You may want to adjust these parameters and exclusions; see the Ninite command-line switch reference and their list of apps.
Sample Output
If you run this script from MAXfocus, you’ll want to run it as an automated task—it’s too long to run as a DSC check. I let it run for an hour. After it completes, the Automated Task window will look like this:
If you scroll in the Details area, you’ll see the full output:
-------------------------------------------------------------- Ninite - Audit before updating - Tue 12/16/2014 - 4:00:51.31 Partial Air : OK - 15.0.0.356 Firefox : OK - 34.0.5 Flash : Update - 15.0.0.246 -> 16.0.0.235 Reader : Update - 10.1.7 -> 11.0.10 Skype : Update - 6.22.0.107 -> 7.0.0.102 -------------------------------------------------------------- Ninite - Update Only - Tue 12/16/2014 - 4:00:59.83 OK Flash : OK Skype : OK Reader : OK -------------------------------------------------------------- Ninite - Audit after updating - Tue 12/16/2014 - 4:07:55.61 OK Air : OK - 15.0.0.356 Firefox : OK - 34.0.5 Flash : OK - 16.0.0.235 Reader : OK - 11.0.10 Skype : OK - 7.0.0.102 -------------------------------------------------------------- Exiting with ExitCode 0
Update May 30, 2019 and July 29, 2019
Important You must get the Ninite executable onto each machine where you want to run this script. Solarwinds RMM does not offer the option of hosting binary files, so you’ll have to have your own static web host (a standard web site, web-enabled Azure storage account, etc.), then you’ll need to use something like the SetUpScripts.ps1 script from this post to download the script to the computer. Keep in mind that scripts in RMM run with highest (SYSTEM account) privileges, so you want your script host to be absolutely secure and unhackable.
As an alternative to automated download, you can just manually copy the executable to a specific folder, e.g. using Take Control File Transfer.
There are several enhancements since the last release in 2015.
Logging
If you’re using the SetUpScripts.ps1 script from this post, you’ll have that environment variable and path. If the path is not there, this script simply writes the output to the same folder where NinitePro.exe is located.
Executable Name
The name of the Ninite executable has been changed from NiniteOne.exe to NinitePro.exe. If you need a different name, you can modify the line of the script that begins with set ProgramExe=
.
Event Logging
By default, the script now writes to the path specified by %IT_Scripts%LogFiles if that path exists.
The script now writes to the Application event log. One information, warning, or error event is written each time the script is run. Deploy the script as a daily automated task, then create two daily (DSC) event log checks in the RMM dashboard:
- Alert if Application log does not contain any event with source “Ninite Script”. This will tell you if the script failed to run that day.
- Alert if Application log contains any Warning or Error event with the source “Ninite Script”. This tells you if a program failed to update, e.g. because it was locked. Check the output in the Tasks tab for more details.
These are the Application events that may be created, all with Source = “Ninite Script”:
Information 101: “Ninite: All programs are up to date. See log at %s.”
Information 102: “Ninite: %i program(s) skipped (possibly unsupported). See log at %s.”
Warning 151: “Ninite: %i program(s) skipped (running/locked). See log at %s.”
Warning 152: “Ninite: %i program(s) skipped but update needed. See log at %s.”
Error 191: “Ninite: Script failed with exit code %i. See log at %s.”
The Script
Save this as NiniteUpdate.cmd. For easier reading and editing, open it in Notepad++. See comments in the script re. various updates since its initial release. As always, test and use at your own risk!
@echo off REM Run Ninite /updateonly on the local computer, optionally caching to local or network path. REM REM Copyright 2019 by Mark Berry, MCB Systems, www.mcbsys.com. REM Free for personal or commercial use. May not be sold. REM No warranties. Use at your own risk. REM REM Param 1: Path to local or network copy of NiniteOne.exe. REM Path only; assumes "NiniteOne.exe" for program name. REM REM Param 2: Path to NiniteDownloads cache. Can be on a network share. Defaults REM to %temp%\NiniteDownloads if not specified. Fails if not accessible. REM REM Assumes you have administrative permissions on the local PC. REM REM Creates/replaces NiniteUpdateSummary.log in %IT_Scripts%\LogFiles or, if that REM doesn't exist, in %ProgramPath%. REM REM 12/11/2014 Initial script. REM REM 12/13/2014 Modify to create and save NiniteUpdateSummary.log as combined log file. REM Individual Ninite runs write to NiniteTemp.log, deleted after use. REM Final audit saved to NiniteAuditAfterUpdate.log. REM REM 12/16/2014 Add exclusions for Avast and AVG (can't update security software), CCleaner REM (vendor doesn't allow update) and Messenger (discontinued). REM REM 01/31/2015 Exclude ".NET 3.5.2", a new Microsoft program. REM REM 03/16/2015 Print program and cache path at beginning of NiniteUpdateSummary.log. REM REM 04/02/2015 Show parameters in log. REM Don't try to write to log if log path (%ProgramPath%) not found. REM REM 04/27/2015 - Fix bug that was putting cache in C:\Program Files (x86)\Advanced Monitoring Agent\scripts\-logfile REM folder when no cache location was specified and script was run from Max RM. REM - Set default cache location to NiniteOne.exe folder (param 1) + \NiniteDownloads. REM REM 11/04/2015 - Max RM agent 9.12.3 introduced a bug that encloses parameters in single quotation marks if they REM were passed in double quotation marks. Strip out single quotation marks around parameters. REM REM 02/24/2017 - Exclude .NET 4.6, 4.6.1, and 4.6.2. REM REM 02/02/2019 - Exclude .NET 4.7, 4.7.1, and 4.7.2. REM - Write log to %IT_Scripts%LogFiles if it exists. REM REM 05/30/2019 - Write events to Windows Application event log indicating success, warning, or failure. REM - Remove lines that deleted logs in old path. REM - Changed default name of executable from NiniteOne.exe to NinitePro.exe. REM REM 07/29/2019 - Detect "Update" still pending in audit after update. That means Ninite is skipping some REM updates, e.g. for Skype Classic or Oracle Java. Report this as Warning event 152. REM =========================================================================================== REM Set up variables REM =========================================================================================== REM This script can be adapted to run another program by modifying the next two lines set ProgramExe=NinitePro.exe REM Exit with 0; exceptions below set /A exitcode=0 REM =========================================================================================== REM Check for parameters REM =========================================================================================== if ###%1###==###### goto NoParam1 goto Param1Found :NoParam1 echo. echo Missing parameter(s) echo. echo Usage: NiniteUpdate.cmd PathToNinite [NiniteDownloadsCache] echo. echo Example: echo. echo NiniteUpdate.cmd "C:\Scripts\Helpers" "\\SRV01\NiniteDownloads" echo. set /A exitcode=1001 goto End :Param1Found REM Strip double quotation marks, if any, from parameter set ProgramPath=%~1 REM Now strip single quotation marks, if any, added by RMM caller bug. REM See http://ss64.com/nt/syntax-dequote.html. set ProgramPath=###%ProgramPath%### set ProgramPath=%ProgramPath:'###=% set ProgramPath=%ProgramPath:###'=% set ProgramPath=%ProgramPath:###=% if ###%2###==###### goto NoParam2 REM RMM adds a -logfile parameter as the last parameter. Ignore that. if ###%2###==###-logfile### goto NoParam2 goto Param2Found :NoParam2 set CachePath=%ProgramPath%\NiniteDownloads goto EchoParams :Param2Found REM Strip double quotation marks, if any, from parameter set CachePath=%~2 REM Now strip single quotation marks, if any, added by RMM caller bug. REM See http://ss64.com/nt/syntax-dequote.html. set CachePath=###%CachePath%### set CachePath=%CachePath:'###=% set CachePath=%CachePath:###'=% set CachePath=%CachePath:###=% :EchoParams REM =========================================================================================== REM Echo parsed parameters REM =========================================================================================== REM echo ProgramPath: %ProgramPath% REM echo ProgramExe: %ProgramExe% REM echo CachePath: %CachePath% REM echo. REM =========================================================================================== REM Check for program path REM =========================================================================================== if exist "%ProgramPath%" goto ProgramPathExists echo Program path "%ProgramPath%" does not exist. Exiting. set /A exitcode=1002 goto End :ProgramPathExists REM =========================================================================================== REM Check for program executable REM =========================================================================================== if exist "%ProgramPath%\%ProgramExe%" goto ProgramExists echo Program executable "%ProgramPath%\%ProgramExe%" does not exist. Exiting. set /A exitcode=1003 goto End :ProgramExists REM =========================================================================================== REM Check for cache path REM =========================================================================================== REM First try to create it if it doesn't exist if not exist "%CachePath%" md "%CachePath%" REM If it still doesn't exist, e.g. if it's on an inaccessible network share, fail if exist "%CachePath%" goto CachePathExists echo Downloads cache path "%CachePath%" does not exist and could not create it. Exiting. set /A exitcode=1004 goto End :CachePathExists REM =========================================================================================== REM Set log path REM =========================================================================================== REM Set new log location, giving priority to %IT_Scripts%LogFiles. set LogPath=%IT_Scripts%LogFiles if not exist "%LogPath%" set LogPath=%ProgramPath% REM Send all output to NiniteUpdateSummary.log file. First redirect overwrites previous log; the rest append. set LogFullPath=%LogPath%\NiniteUpdateSummary.log REM =========================================================================================== REM Run Ninite three times with various parameters REM =========================================================================================== set CommonParams=/silent "%LogPath%\NiniteTemp.log" /disableshortcuts /exclude ".NET" ".NET 3.5" ".NET 4" ".NET 4.5" ".NET 4.5.1" ".NET 4.5.2" ".NET 4.6" ".NET 4.6.1" ".NET 4.6.2" ".NET 4.7" ".NET 4.7.1" ".NET 4.7.2" Avast AVG CCleaner Essentials Messenger Office OneDrive OpenOffice Silverlight SkyDrive TeamViewer set CacheParam=/cachepath "%CachePath%" echo NiniteUpdate.cmd > "%LogFullPath%" echo. >> "%LogFullPath%" echo Program: %ProgramPath%\%ProgramExe% >> "%LogFullPath%" echo Cache param: %CacheParam% >> "%LogFullPath%" echo Common params: %CommonParams% >> "%LogFullPath%" echo Log file: %LogFullPath% >> "%LogFullPath%" REM =========================================================================================== REM Audit before update REM =========================================================================================== echo. >> "%LogFullPath%" echo -------------------------------------------------------------- >> "%LogFullPath%" echo Ninite - /audit before updating - %date% - %time% >> "%LogFullPath%" echo. >> "%LogFullPath%" "%ProgramPath%\%ProgramExe%" /audit %CommonParams% %CacheParam% set /a errorcode=%errorlevel% if %errorcode% EQU 0 goto LogAuditBeforeUpdate echo Running first %ProgramExe% /audit failed with ErrorLevel %errorcode%. Exiting. set /A exitcode=1100+%errorcode% goto WriteToEventLogAndEnd :LogAuditBeforeUpdate REM Print lines that do NOT contain the string ": Not installed" type "%LogPath%\NiniteTemp.log" | find /V ": Not installed" >> "%LogFullPath%" del "%LogPath%\NiniteTemp.log" REM =========================================================================================== REM Update REM =========================================================================================== echo. >> "%LogFullPath%" echo -------------------------------------------------------------- >> "%LogFullPath%" echo Ninite - /updateonly - %date% - %time% >> "%LogFullPath%" echo. >> "%LogFullPath%" "%ProgramPath%\%ProgramExe%" /updateonly %CommonParams% %CacheParam% set /a errorcode=%errorlevel% if %errorcode% EQU 0 goto LogUpdate echo Running %ProgramExe% /updateonly failed with ErrorLevel %errorcode%. Exiting. set /A exitcode=1100+%errorcode% goto WriteToEventLogAndEnd :LogUpdate REM Count occurrences of "Skipped (program running/locked)" and save in variable REM "Find" emits a line with three space-separated "tokens." Save the count appears from the third token. for /f "tokens=3" %%f in ('find /c ": Skipped (program running/locked)" "%LogPath%\NiniteTemp.log"') do set /a SkippedLocked=%%f type "%LogPath%\NiniteTemp.log" >> "%LogFullPath%" del "%LogPath%\NiniteTemp.log" REM =========================================================================================== REM Audit after update REM =========================================================================================== echo. >> "%LogFullPath%" echo -------------------------------------------------------------- >> "%LogFullPath%" echo Ninite - /audit after updating - %date% - %time% >> "%LogFullPath%" echo. >> "%LogFullPath%" "%ProgramPath%\%ProgramExe%" /audit %CommonParams% %CacheParam% set /a errorcode=%errorlevel% if %errorcode% EQU 0 goto LogAuditAfterUpdate echo Running second %ProgramExe% /audit failed with ErrorLevel %errorcode%. Exiting. set /A exitcode=1100+%errorcode% goto WriteToEventLogAndEnd :LogAuditAfterUpdate REM In an audit run after doing updates, "Update" means Ninite could/would not update (e.g. Skype Classic, Oracle Java) REM Count occurrences of "Update" and save in variable. Will report as Warning event 152. for /f "tokens=3" %%f in ('find /c ": Update" "%LogPath%\NiniteTemp.log"') do set /a SkippedUpdate=%%f REM In an audit run, "Skipped" means Ninite is ignoring it, maybe because it's no longer supported REM The programs that could not be updated contain the string "->" but we already counted SkippedLocked above REM Count occurrences of "Skipped" and save in variable. Will report as Information event 102. for /f "tokens=3" %%f in ('find /c ": Skipped" "%LogPath%\NiniteTemp.log"') do set /a SkippedOther=%%f type "%LogPath%\NiniteTemp.log" | find /V ": Not installed" >> "%LogFullPath%" REM Save final full log as NiniteAuditAfterUpdate.log (delete old audit first) del "%LogPath%\NiniteAuditAfterUpdate.log" ren "%LogPath%\NiniteTemp.log" "NiniteAuditAfterUpdate.log" :WriteToEventLogAndEnd REM echo exitcode = %exitcode% REM echo SkippedLocked = %SkippedLocked% REM echo SkippedOther = %SkippedUpdate% REM echo SkippedOther = %SkippedOther% REM %message% was not expanding in "eventcreate". Using delayed variable expansion and !message! fixes that. setlocal EnableDelayedExpansion REM Write only one event to event log. First check for Error condition, then Warning, then Information. REM Redirect output of "eventcreate" to nul so it doesn't write to stdout/stderr. if %exitcode% GTR 0 ( set message=Script failed with exit code %ExitCode%. eventcreate /l Application /t Error /so "Ninite Script" /id 191 /d "Ninite: !message! See log at !LogFullPath!." >nul 2>&1 echo "Script failed with exit code %ExitCode%" >> "%LogFullPath%" goto PrintLogAndEnd ) if %SkippedLocked% GTR 0 ( REM Note we need to escape the closing parentheses with a caret or it would end the if statement set message=%SkippedLocked% program(s^) skipped (running/locked^). eventcreate /l Application /t Warning /so "Ninite Script" /id 151 /d "Ninite: !message! See log at !LogFullPath!." >nul 2>&1 goto PrintLogAndEnd ) if %SkippedUpdate% GTR 0 ( set message=%SkippedUpdate% program(s^) skipped but update needed. eventcreate /l Application /t Warning /so "Ninite Script" /id 152 /d "Ninite: !message! See log at !LogFullPath!." >nul 2>&1 goto PrintLogAndEnd ) if %SkippedOther% GTR 0 ( set message=%SkippedOther% program(s^) skipped (possibly unsupported^). eventcreate /l Application /t Information /so "Ninite Script" /id 102 /d "Ninite: !message! See log at !LogFullPath!." >nul 2>&1 goto PrintLogAndEnd ) set message=All programs are up to date. eventcreate /l Application /t Information /so "Ninite Script" /id 101 /d "Ninite: !message! See log at !LogFullPath!." >nul 2>&1 goto PrintLogAndEnd :PrintLogAndEnd echo. >> "%LogFullPath%" echo -------------------------------------------------------------- >> "%LogFullPath%" echo. >> "%LogFullPath%" REM Output a summary as first line to appear in the RMM dashboard. echo %message% echo -------------------------------------------------------------- REM Type log to stdout so it will appear in RMM dashboard type "%LogFullPath%" echo Exiting with ExitCode %exitcode% >> "%LogFullPath%" :End REM Display ExitCode in stdout even if log file not available echo Exiting with ExitCode %exitcode% exit /b %exitcode%
Need help with custom scripting? Contact MCB Systems.
Hi Mark,
This is a great script. I have not worked with the Automated Tasks in MaxFocus that much. Can you elaborate how you actually run it in the Dashboard?
Great work!
Thanks,
Ian
Ian, you will need to get the NiniteOne.exe program onto the machine where the script will run. You can do this manually, or write a script to download from a server.
Because this script can take several minutes to run, I set it up as a Windows Automated Task (as opposed to running it as a DSC or 24×7 Script Check). Basic instructions are available in the Dashboard Help: https://dashboard.systemmonitor.us/helpcontents/index.html?add_a_check.htm.
If you’d like direct support configuring all this, we can set up a short consult. Contact me: http://www.mcbsys.com/contact.
Thanks Mark. I have read through the Basic Instructions already and was more wondering about how you executed the script using but you put me on the right path. I’ll play around with it and see if I can get it to work. Knowing that you copy it to the local system is helpful as apposed to having the Agent push it down.
I actually host a bunch of scripts and helpers (like NiniteOne.exe) in a private area of my web site and use a DSC script to pull those down and store them on the local drive every day. I haven’t published that download script but you may be able to use something like this: http://www.fixitscripts.com/problems/script-required.
Hello
Would like to consult with you to get this script working in GFI. Would that be possible?
Jon, absolutely. Replying via email.
Hi Mark. I would like to discuss this script with you if you have some time. Let me know if you are still available and willing. Thank you.
Is there a reason you like using Ninite over the third-party patching in Max/Solarwinds? I haven’t done a side by side comparison yet but it seems like they both cover most of the same products.
@Wayne, a couple years ago, I tried desperately to get MaxRM patching to work at a client site. After several weeks (or was it months?) of failures, I gave up and switched to native Windows Update for Windows patches (later switched to WSUS) and Ninite for 3rd-party patches. You may have better luck with MaxRM–it’s been a couple years, as I say, and this client had some special circumstances.