Name

global.WindowsInstalledSoftware

Description

Contains functions for parsing JSON formatted Windows - Installed Software information Please keep consistent with the WindowsInstalledSoftware MID server script include for testing purposes, as well as in case Classic mode is enabled on the probe

Script

var WindowsInstalledSoftware = Class.create();

WindowsInstalledSoftware.prototype = {
  process : function(output, related_data) {
  	related_data.packages = [];

  	var jsonPayload = JSON.parse(output);
  	// Using hash to make sure we get no dups (by name + version).
  	var softwareList = this.getAllPackages(jsonPayload, related_data);

  	for (var sw in softwareList){
  		// Special case for OS IDs
  		if (sw === "osId:prodId:dProdId")
  			related_data.osPackage = softwareList[sw];
  		else
  			related_data.packages.push(softwareList[sw]);
  	}

  	related_data.caption = jsonPayload.wmi.Win32_OperatingSystem.Caption;
  	related_data.osVersion = jsonPayload.wmi.Win32_OperatingSystem.Version;
  },

  getAllPackages: function(payload, related_data) {
  	var registryKeys = payload.registry;
  	var softwareList = {};
  	var productIds = {};
  	var officeLicenses = {};

  	for(var reg in registryKeys) {
  		var pkg = registryKeys[reg];
  		var pkgPath = pkg.Path;

  		if (pkgPath.includes("\\Package_")){
  			// Need to process hotfixes
  			var kb = this.parseInstalledKBs(pkg);

  			if (kb)
  				softwareList[kb.key] = kb;
  		}
  		else if (pkgPath.includes("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer")){
  			// Need to process IE details
  			var iePackage = this.parseIEDetails(pkg);

  			if (!JSUtil.nil(iePackage))
  				softwareList["iePackage"] = iePackage;

  			continue;
  		}
  		else if (pkgPath.includes("Adobe Acrobat") && pkgPath.includes("AVEntitlement")) {
  			related_data.adobe_acrobat_edition = this.getValueFromPackage(pkg, "iEntitlementLevel");
  		}
  		else{
  			if (pkgPath == "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion" || pkgPath == "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion"){
  				// Need to process OSIDs

  				var osId = this.parseOSIDs(pkg);

  				if (!JSUtil.nil(osId)){
  					softwareList["osId:prodId:dProdId"] = osId;
  					// Only continue if this is OS IDs section - otherwise parse package.
  					continue;
  				}
  			}
  			else if (pkgPath.startsWith("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Office") || pkgPath.startsWith("HKEY_LOCAL_MACHINE\\Software\\Wow6432Node\\Microsoft\\Office")){
  				// This is a Office!

  				// Grabs the string after the last slash and removes curly brackets if there are any
  				var officeUuidRegex = /.*\\\{?(.*?)\}?$/mgi;

  				var prodId = pkg.ProductId;
  				var dProdId = pkg.DigitalProductId;
  				var uuid = pkg.Path;

  				// Try and get the UUID from the path
  				var uuidDetails = officeUuidRegex.exec(pkg.Path);
  				if (uuidDetails && uuidDetails[1])
  					uuid = uuidDetails[1];

  				officeLicenses[uuid] = {};
  				officeLicenses[uuid].productid = prodId;
  				officeLicenses[uuid].digitalproductid = dProdId;
  			}

  			var softwareItem = this.parseSoftwareAndProduct(pkg, related_data);
  			if (!JSUtil.nil(softwareItem)){
  				if (JSUtil.nil(softwareList[softwareItem.uniqueName]) || softwareList[softwareItem.uniqueName] == null || softwareList[softwareItem.uniqueName] == undefined)
  					softwareList[softwareItem.uniqueName] = softwareItem;
  				else
  					softwareList[softwareItem.uniqueName] = this.mergeJsonObjects(softwareList[softwareItem.uniqueName], softwareItem);

  				if (softwareList[softwareItem.uniqueName] != null && !JSUtil.nil(softwareItem.msi_id) && !JSUtil.nil(officeLicenses[softwareItem.msiID]))
  					softwareList[softwareItem.uniqueName].digital_product_id = officeLicenses[softwareItem.msiID].digitalproductid;
  			}
  		}
  	}
  	// Finish processing adobe acrobat if neccesary
  	if (related_data.adobe_acrobat != null) {
  		// If we found the edition in registry, apply that instead.
  		var acrobat_pkg = related_data.adobe_acrobat;
  		acrobat_pkg = this.setAttributeOnlyIfHasValue(acrobat_pkg, "edition", related_data.adobe_acrobat_edition);
  		
  		// Merge/Re-Add to payload as neccessary
  		if (!softwareList[acrobat_pkg.uniqueName])
  			softwareList[acrobat_pkg.uniqueName] = related_data.adobe_acrobat;
  		else
  			softwareList[acrobat_pkg.uniqueName] = this.mergeJsonObjects(softwareList[acrobat_pkg.uniqueName], acrobat_pkg);
  		
  		// cleanup related_data of the unneeded adobe properties
  		delete related_data.adobe_acrobat;
  		delete related_data.adobe_acrobat_edition;
  	}
  	return softwareList;
  },

  getValueFromPackage: function(pkg, attribute){
  	return pkg[attribute] || '';
  },

  parseIEDetails: function (pkg){
  	var svcVersion = pkg.svcVersion;
  	var ver = pkg.Version;

  	if (JSUtil.nil(svcVersion) && JSUtil.nil(ver))
  		return;

  	var iePackage = {};
  	iePackage.name = "Internet Explorer";
  	iePackage.vendor = "Microsoft";

  	// Version should work for IE 4.0+. svcVersion is new to IE 10. 
  	iePackage.version = svcVersion ? svcVersion : ver;

  	return iePackage;
  },

  parseOSIDs: function (pkg){
  	var prodId = pkg.ProductId;
  	var dProdId = pkg.DigitalProductId;

  	if (!JSUtil.nil(prodId) || !JSUtil.nil(dProdId)){
  		return {
  			product_id: prodId,
  			digital_product_id: dProdId
  		};
  	}
  },

  parseInstalledKBs: function(pkg){
  	var kbRegEx = /Package_.*?_(KB\d+).*?([\d\.]*)\./mgi;
  	var installName = pkg.InstallName;

            /* Refer the below articles for more information on install date calculation
                1. https://forum.bigfix.com/t/how-to-find-install-date-of-windows-patch-delpoyed-via-bigfix/19623/2
                2. https://stackoverflow.com/questions/51547064/convert-18-digit-ldap-filetime-timestamps-to-human-readable-date
            */
            var installTimeHigh = parseInt(pkg.InstallTimeHigh);
            var installTimeLow = parseInt(pkg.InstallTimeLow);
            var installDate = ((((installTimeHigh * 4294967296) + installTimeLow) / 10000000) - 11644473600);

  	var kbDetails;
  	var kbPrefix = "Hotfix";

  	// Extract the KB number and Version using regex
  	kbDetails = kbRegEx.exec(installName);
  	if (kbDetails && kbDetails[1]){
  		var kb = {};
  		var key = kbDetails[1];
  		kb.name = kbPrefix + " (" + key + ")";
  		kb.key = key;
  		kb.package_name = key;
  		kb.vendor = "Microsoft Corporation";
  		kb.install_date = parseInt(installDate) + "";
  		// Fixed sys_id for Unknown
  		kb.manufacturer = "0e8b8e650a0a0b3b004f285ffbb1a4fc";
  		if (kbDetails[2])
  			kb.version = kbDetails[2];

  		return kb;
  	}

  	return;
  },

  parseSoftwareAndProduct: function(pkg, related_data){
  	var softwareItem = {};

  	var displayName = this.getValueFromPackage(pkg, "DisplayName");
  	var parentDisplayName = this.getValueFromPackage(pkg, "ParentDisplayName");
  	var displayVersion = this.getValueFromPackage(pkg, "DisplayVersion");
  	var publisher = this.getValueFromPackage(pkg, "Publisher");
  	var uninstallString = this.getValueFromPackage(pkg, "UninstallString");
  	var installDate = this.getValueFromPackage(pkg, "InstallDate");
  	var msiID = this.parseMsiId(uninstallString);
  	var pid = this.getValueFromPackage(pkg, "ProductID");
  	var installLocation = this.getValueFromPackage(pkg, "InstallLocation");
  	var validPID = true;
  	if (pid == null || pid.length == 0 || pid.toLowerCase() == "none")
  		validPID = false;

  	if (JSUtil.nil(displayName) || displayName === "")
  		return;

  	var uniqueName = this.getUniqueName(displayName, displayVersion);

  	softwareItem = {};
  	softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "uniqueName", uniqueName);
  	softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "name", displayName);
  	softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "version", displayVersion);
  	softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "vendor", publisher);
  	softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "part_of", parentDisplayName);
  	softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "uninstall_string", uninstallString);
  	softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "install_date", installDate);
  	softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "install_location", installLocation);

  	if (validPID)
  		softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "product_id", pid);

  	if (msiID != null && msiID.length > 0 && msiID.toLowerCase() != "none" && msiID != "")
  		softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "msi_id", msiID);
  	
  	if (/Acrobat/.test(displayName) && !JSUtil.nil(uninstallString) && (uninstallString.indexOf("{") >= 0) && (uninstallString.indexOf("}") >= 0)) {
  		var editionString = uninstallString.split("{")[1];
  		editionString = editionString.split("}")[0];
  		if (!JSUtil.nil(editionString)) {
  			var splitEdition = editionString.split("-");
  			if (splitEdition.length >= 4)
  				softwareItem = this.setAttributeOnlyIfHasValue(softwareItem, "edition", splitEdition[3]);
  		}
  		related_data.adobe_acrobat = softwareItem;
  		return;
  	}

  	return softwareItem;
  },

  getUniqueName: function(name, version) {
  	return name + " " + version;
  },

  setAttributeOnlyIfHasValue: function(obj, att, value){
  	if (!JSUtil.nil(value) && value != null && value.length > 0 && value.toLowerCase() != "none" && value != "")
  		obj[att] = value;

  	return obj;
  },

  mergeJsonObjects: function(obj1, obj2){
  	for (var key in obj2){
  		if (!obj1.hasOwnProperty(key) || JSUtil.nil(obj1[key]) || obj1[key] == null || obj1[key].length == 0 || obj1[key].toLowerCase() == "none" || obj1[key] == "")
  			obj1[key] = obj2[key];
  	}

  	return obj1;
  },

  parseMsiId: function(str) {
  	var msiID = "";

  	if (str && str.toLowerCase().indexOf("msiexec") > -1) {
  		var start = str.indexOf("{");
  		var finalString = str.substring(start+1);
  		var end = finalString.indexOf("}");
  		msiID = finalString.substring(0, end);
  	}

  	return msiID;
  },
  type: "WindowsInstalledSoftware"
};

Sys ID

e6ece2f2733300102535b7385ef6a72d

Offical Documentation

Official Docs: