Skip to content

Instantly share code, notes, and snippets.

@Bill-Stewart
Last active August 10, 2023 09:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Bill-Stewart/9379a8df293de418ed96ee6ea82c4459 to your computer and use it in GitHub Desktop.
Save Bill-Stewart/9379a8df293de418ed96ee6ea82c4459 to your computer and use it in GitHub Desktop.
FixUnquotedServicePaths.js
// FixUnquotedServicePaths.js
// WSH script written by Bill Stewart (bstewart AT iname.com)
//
// Corrects each service on the local machine that has an "unquoted service
// path" and logs its actions to the application event log.
//
// The idea here is to run this as a computer startup script, so that unquoted
// service paths will get identified and corrected automatically at every
// reboot.
//
// (In 99.9% of real-world cases, this is not an actual security vulnerability,
// because by default this "vulnerability" can only be exploited by an account
// that's already a member of the local Administrators group. However, this
// script will remediate this condition to prevent vulnerability scanning tools
// from erroneously identifying this condition as a vulnerability and causing
// unnecessary wasted time to "fix" it.)
// Version history:
//
// 1.0.0 (2022-04-19)
// * Initial version.
//
// 1.0.1 (2022-04-28)
// * Minor adjustment to regex to account for leading spaces.
//
// 1.0.2 (2022-05-04)
// * Minor bug fix (log event if WMI connection failed).
//
// 1.0.3 (2022-11-01)
// * Minor regex tweak to account for potential mismatched quotes in command.
// Script logs to the Application event log (source WSH)
var EventLogText = "Script: " + WScript.ScriptName + "\r\n" +
"This script fixes any services on this computer with an 'unquoted service path'.";
// Global SWbemServices object (after ConnectWMI function succeeds)
var SWbemServices = null;
// Test if using /test parameter
var TestMode = false;
// Returns n as a hex string.
function hex(n) {
return n < 0 ? (n + Math.pow(2,32)).toString(0x10).toUpperCase() :
n.toString(0x10).toUpperCase();
}
// Gets the computer's SWbemServices object.
function ConnectWMI() {
var result = 0;
try {
var sWBemLocator = new ActiveXObject("WbemScripting.SWbemLocator");
SWbemServices = sWBemLocator.ConnectServer(".","root\\CIMV2");
}
catch(err) {
result = err.number;
EventLogText += "\r\n\r\nError 0x" + hex(result) + " connecting to WMI";
}
return result;
}
// Returns a properly quoted service command string.
function quoteServiceCommandString(commandString) {
var result = commandString;
var re = /^\s*(?:"?(.+\.exe)"?)(\s+(?:.*))?/i;
var matches = re.exec(commandString);
if ( matches != null ) {
if ( (matches[1].charAt(0) != '"') && (matches[1].indexOf(" ") != -1) ) {
result = '"' + matches[1] + '"';
if ( matches[2] != "" ) {
result += matches[2];
}
}
}
return result;
}
// Updates a service's command (i.e., the ImagePath value in the registry).
function updateServiceCommand(service,serviceCommand) {
var oldCommand = service.PathName;
var result = 0;
if ( ! TestMode ) {
result = service.Change(null, // DisplayName
serviceCommand, // PathName
null, // ServiceType
null, // ErrorControl
null, // StartMode
null, // DesktopInteract
null, // StartName
null, // StartPassword
null, // LoadOrderGroup
null, // LoadOrderGroupDependencies
null); // ServiceDependencies
}
EventLogText += "\r\n\r\nService: " + service.Name + "\r\n";
switch ( result ) {
case 0: {
EventLogText += "Old ImagePath: " + oldCommand + "\r\n" +
"Updated ImagePath: " + serviceCommand;
break;
}
case 1: {
EventLogText += "ERROR: Not Supported";
break;
}
case 2: {
EventLogText += "ERROR: Access Denied";
break;
}
case 3: {
EventLogText += "ERROR: Dependent Services Running";
break;
}
case 4: {
EventLogText += "ERROR: Invalid Service Control";
break;
}
case 5: {
EventLogText += "ERROR: Service Cannot Accept Control";
break;
}
case 6: {
EventLogText += "ERROR: Service Not Active";
break;
}
case 7: {
EventLogText += "ERROR: Service Request Timeout";
break;
}
case 8: {
EventLogText += "ERROR: Unknown Failure";
break;
}
case 9: {
EventLogText += "ERROR: Path Not Found";
break;
}
case 10: {
EventLogText += "ERROR: Service Already Running";
break;
}
case 11: {
EventLogText += "ERROR: Service Database Locked";
break;
}
case 12: {
EventLogText += "ERROR: Service Dependency Deleted";
break;
}
case 13: {
EventLogText += "ERROR: Service Dependency Failure";
break;
}
case 14: {
EventLogText += "ERROR: Service Disabled";
break;
}
case 15: {
EventLogText += "ERROR: Service Logon Failed";
break;
}
case 16: {
EventLogText += "ERROR: Service Marked For Deletion";
break;
}
case 17: {
EventLogText += "ERROR: Service No Thread";
break;
}
case 18: {
EventLogText += "ERROR: Status Circular Dependency";
break;
}
case 19: {
EventLogText += "ERROR: Status Duplicate Name";
break;
}
case 20: {
EventLogText += "ERROR: Status Invalid Name";
break;
}
case 21: {
EventLogText += "ERROR: Status Invalid Parameter";
break;
}
case 22: {
EventLogText += "ERROR: Status Invalid Service Account";
break;
}
case 23: {
EventLogText += "ERROR: Status Service Exists";
break;
}
case 24: {
EventLogText += "ERROR: Service Already Paused";
break;
}
case 25: {
EventLogText += "ERROR: Other";
break;
}
}
return result;
}
function main() {
TestMode = WScript.Arguments.Named.Exists("test");
var result = ConnectWMI();
var logEvent = result != 0;
if ( result == 0 ) {
var services = new Enumerator(SWbemServices.ExecQuery("SELECT Name,PathName FROM Win32_Service"));
for ( ; ! services.atEnd(); services.moveNext() ) {
var service = services.item();
var properlyQuotedCommandString = quoteServiceCommandString(service.PathName);
if ( service.PathName != properlyQuotedCommandString ) {
logEvent = true;
result = updateServiceCommand(service,properlyQuotedCommandString);
if ( result != 0 ) {
break;
}
}
}
}
if ( logEvent ) {
var wshShell = new ActiveXObject("WScript.Shell");
// LogEvent method 1st parameter is event type (0 = success, 1 = error)
wshShell.LogEvent((result == 0 ? 0 : 1),EventLogText);
}
return result;
}
WScript.Quit(main());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment