Name

global.WindowsInstalledSoftwareLegacy

Description

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

Script

var WindowsInstalledSoftwareLegacy = Class.create();

WindowsInstalledSoftwareLegacy.prototype = {
  /**
   * Runs the probe instance
   */    
  process : function(output, related_data) {  
  	related_data.packages = [];
  	
  	var registry = output.Registry;
      if (JSUtil.nil(registry))
          return;
      
      var softwareList = this.getSoftware(registry);

      for (var sw in softwareList)
          related_data.packages.push(softwareList[sw]);
  	
  	var osPackage = {};
  	related_data.osPackage = this._setOSIDs(osPackage, registry);
  	related_data.caption = output.Win32_OperatingSystem.Caption;
  	related_data.osVersion = output.Win32_OperatingSystem.Version;
  	
  	var iePkgObj = this.getIEPackage(registry);
  	if (JSUtil.notNil(iePkgObj))
          related_data.packages.push(iePkgObj);
  },
  
  getSoftware: function(registry) {
      var softwareList = {};
      var productIds = this.getProductIds(registry, softwareList); //get product ID as well as software entries.
      var officeLic = this.getOfficeLicenses(registry);

      var softwareReg = [];
      softwareReg.push("HKEY_LOCAL_MACHINE.Software.Microsoft.Windows.CurrentVersion.Uninstall");
      softwareReg.push("HKEY_LOCAL_MACHINE.Software.Wow6432Node.Microsoft.Windows.CurrentVersion.Uninstall");

      for (var i = 0; i < softwareReg.length; i++) {
          var node = this.findRegistryNode(registry, softwareReg[i]);
          if (!node)
              continue;

          this.parseSoftware(node, softwareList, productIds, officeLic);
      }

  	this.updateAdobeAcrobat(registry, softwareList);
  	
      return softwareList;
  },
  
  parseSoftware: function(node, softwareList, productIds, officeLic) {
      var nodeArray = g_array_util.ensureArray(node.entry);
      for (var dataKey = 0; dataKey < nodeArray.length; dataKey++) {
          var displayName = this.findNodeValueWithAttribute(nodeArray[dataKey], "DisplayName");
          var parentDisplayName = this.findNodeValueWithAttribute(nodeArray[dataKey], "ParentDisplayName");
          var displayVersion = this.findNodeValueWithAttribute(nodeArray[dataKey], "DisplayVersion");
          var publisher = this.findNodeValueWithAttribute(nodeArray[dataKey], "Publisher");
          var uninstallString = this.findNodeValueWithAttribute(nodeArray[dataKey], "UninstallString");
          var installDate = this.findNodeValueWithAttribute(nodeArray[dataKey], "InstallDate");
          var msiID = this.parseMsiId(uninstallString);

          if (!displayName)
              continue;

          var uniqueName = this.getUniqueName(displayName, displayVersion);
  		
          // Sometimes we encounter two entries of that have the same name, but one has the msi_id and the
          // other one doesn't. In which case we want to give it another chance matching the office license.
          if (softwareList[uniqueName]) {
              if (JSUtil.nil(msiID) || JSUtil.notNil(softwareList[uniqueName].msi_id)) {
  				//populate detailed information 
  				softwareList[uniqueName].part_of = parentDisplayName;
  				softwareList[uniqueName].install_date = installDate;
                  continue;
  			}
          }

          if (displayName == "detectedInvalidXMLCharacter") {
              this.log("Detected an invalid character in registry for " + displayName , 
                      'Windows - Installed Software Sensor', this.getEccQueueId(), null);
              continue;
          }
  		
          softwareList[uniqueName] = {};
          softwareList[uniqueName].name = displayName;
          softwareList[uniqueName].version = displayVersion;
          softwareList[uniqueName].vendor = publisher;
          softwareList[uniqueName].part_of = parentDisplayName;
          softwareList[uniqueName].uninstall_string = uninstallString;
          softwareList[uniqueName].install_date = installDate;
  		
  		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)
  						softwareList[uniqueName].edition = splitEdition[3];
  				}
  			softwareList.adobe_acrobat = softwareList[uniqueName];
  		}

          // If product id is non-existent, don't bother since the following info is for creating licenses.
          // And without a product id, we just wouldn't do it.
          if (JSUtil.nil(productIds[uniqueName]))
              continue;

          softwareList[uniqueName].product_id = productIds[uniqueName];

          if (JSUtil.nil(msiID) || JSUtil.nil(officeLic[msiID]))
              continue;

          softwareList[uniqueName].msi_id = msiID;
          softwareList[uniqueName].digital_product_id = officeLic[msiID].digitalproductid;
      }

      return softwareList;
  },

  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;
  },
  
  getIEPackage: function(registry) {
  	var regKey = "HKEY_LOCAL_MACHINE.Software.Microsoft.Internet Explorer";
      var node = this.findRegistryNode(registry, regKey);
      var svcVersion = this.findNodeValueWithAttribute(node, "svcVersion");
  	var version = this.findNodeValueWithAttribute(node, "Version");
  	
  	// Check if we can detect IE
  	if (JSUtil.nil(svcVersion) && JSUtil.nil(version))
  	    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 : version;
  	
  	regKey = "HKEY_LOCAL_MACHINE.Software.Microsoft.Internet Explorer.Registration";
      node = this.findRegistryNode(registry, regKey);
  	var productId = this.findNodeValueWithAttribute(node, "ProductId");
  	
  	if (!JSUtil.nil(productId)) 
  		iePackage.product_id = productId;
  		
      return iePackage;
  },

  _setOSIDs: function(osPackage, registry) {
      var node = this.findRegistryNode(registry, 
              "HKEY_LOCAL_MACHINE.Software.Microsoft.Windows.CurrentVersion");
      var node2 = this.findRegistryNode(registry, 
              "HKEY_LOCAL_MACHINE.Software.Microsoft.Windows NT.CurrentVersion");

      if (!node || !node2)
          return osPackage;

      var prodId = this.findNodeValueWithAttribute(node, "ProductId");

      if (JSUtil.nil(prodId) || prodId == "") //Try it again at a diff location (like for Vista)...                
          prodId = this.findNodeValueWithAttribute(node2, "ProductId");

      var dProdId = this.findNodeValueWithAttribute(node2, "DigitalProductID");

      osPackage.product_id = prodId;
      osPackage.digital_product_id = dProdId;

      return osPackage;
  },

  getProductIds: function(registry, softwareList) {
      var prodIdReg = [];
      prodIdReg.push("HKEY_LOCAL_MACHINE.Software.Microsoft.Windows.CurrentVersion.Installer.UserData");
      prodIdReg.push("HKEY_LOCAL_MACHINE.Software.Wow6432Node.Microsoft.Windows.CurrentVersion.Installer.UserData");

      var productIds = {};
      for (var i = 0; i < prodIdReg.length; i++) {
          var node = this.findRegistryNode(registry, prodIdReg[i]);
          if (!node)
             continue;

          productIds = this.parseProductIds(node, productIds, softwareList);
      }

      return productIds;
  },

  parseProductIds: function(node, productIds, softwareList) {
      var nodeArray = g_array_util.ensureArray(node.entry);
      for (var dataKey=0; dataKey < nodeArray.length; dataKey++) {
          var products = this.findNodeWithAttribute(nodeArray[dataKey], "Products");
          if (!products)
              continue;

          var nodeArray2 = g_array_util.ensureArray(products.entry);
          for (var dataKey2 = 0; dataKey2 < nodeArray2.length; dataKey2++) {
              var installProperties = this.findNodeWithAttribute(nodeArray2[dataKey2], "InstallProperties");
              var publisher = this.findNodeValueWithAttribute(installProperties, "Publisher");
              var pid = this.findNodeValueWithAttribute(installProperties, "ProductID");
              var name = this.findNodeValueWithAttribute(installProperties, "DisplayName");
              var version = this.findNodeValueWithAttribute(installProperties, "DisplayVersion");

              if (!name)
                  continue;

              var validPID = true;
              if (pid == null || pid.length == 0 || pid.toLowerCase() == "none")
                  validPID = false;

              // As it turned out, sometimes customers don't have their software in the uninstall resgtries (due to 
              // improper imaging or deliberate efforts), but we should still fish it out this Products registries 
              // first.
              var uniqueName = this.getUniqueName(name, version);
              if (!softwareList[uniqueName]) {
                  softwareList[uniqueName] = {};
                  softwareList[uniqueName].name    = name;
                  softwareList[uniqueName].version = version ;
                  softwareList[uniqueName].vendor  = publisher;
                  if (validPID)
                      softwareList[uniqueName].product_id  = pid;
              }

              if (validPID)
                  productIds[uniqueName] = pid;
          }
      }

      return productIds;
  },

  getOfficeLicenses: function(registry) {
      officeLicenseReg = [];
      officeLicenseReg.push("HKEY_LOCAL_MACHINE.Software.Microsoft.Office");
      officeLicenseReg.push("HKEY_LOCAL_MACHINE.Software.Wow6432Node.Microsoft.Office");

      var officeLicenses = {};
      for (var i = 0; i < officeLicenseReg.length; i++) {
          var node = this.findRegistryNode(registry, officeLicenseReg[i]);
          if (!node)
              continue;

          officeLicenses = this.parseOfficeLicense(node, officeLicenses);
      }

      return officeLicenses;
  },

  parseOfficeLicense: function(node, officeLicenses) {
      var nodeArray = g_array_util.ensureArray(node.entry);
      for (var dataKey = 0; dataKey < nodeArray.length; dataKey++) {
          var registrations = this.findNodeWithAttribute(nodeArray[dataKey], "Registration");

          if (!registrations)
              continue;

          var nodeArray2 = g_array_util.ensureArray(registrations.entry);
          for (var dataKey2 = 0; dataKey2 < nodeArray2.length; dataKey2++) {
              var productID = this.findNodeValueWithAttribute(nodeArray2[dataKey2], "ProductID");
              var digitalProductID = this.findNodeValueWithAttribute(nodeArray2[dataKey2], "DigitalProductID");


              var uuid = new String(nodeArray2[dataKey2]['@key']);

              if (uuid.substring(0, 1) == "{")
                  uuid = uuid.substring(1, uuid.length-1);

              officeLicenses[uuid] = {};
              officeLicenses[uuid].productid = productID;
              officeLicenses[uuid].digitalproductid = digitalProductID;
          }
      }

      return officeLicenses;
  },
  
  // Find the proper edition for Adobe Acrobat (pro vs standard)
  updateAdobeAcrobat: function(registry, softwareList) {
      // Did we find adobe acrobat?  If not, just skip this.
      if (JSUtil.nil(softwareList.adobe_acrobat))
          return;
  	
      // There are multiple "*" in the key so we need to iterate through
      var users_node = this.findRegistryNode(registry, "HKEY_USERS");
      if (!users_node) {
          delete softwareList.adobe_acrobat;
          return;
      }
      var users_node_array = g_array_util.ensureArray(users_node.entry);
      for (var dataKey=0; dataKey < users_node_array.length; dataKey++) {
          var tracks = this.findRegistryNode(users_node_array[dataKey], "SOFTWARE.Adobe.Adobe Acrobat");
          if (!tracks) {
              delete softwareList.adobe_acrobat;
              return;
          }
          var tracks_array = g_array_util.ensureArray(tracks.entry);
          for (var dataKey2 = 0; dataKey2 < tracks_array.length; dataKey2++) {
              var entitlement_node = this.findRegistryNode(tracks_array[dataKey2], "AVEntitlement");
              var entitlementLevel = this.findNodeValueWithAttribute(entitlement_node, "iEntitlementLevel");

              if (!JSUtil.nil(entitlementLevel) && (entitlementLevel == 200 || entitlementLevel == 300)) {
                  softwareList.adobe_acrobat.edition = entitlementLevel;
                  return;
              }
          }
  		
      }
  },
  

  getUniqueName: function(name, version) {
      return name + " " + version;
  },
  
  /********************************************** 
   * Manage the Windows installed software xml
   *
   * Example payload:
   *   <results probe_time="6313">
   *     <result>
   *       <Registry>
   *         <entry key="HKEY_LOCAL_MACHINE">
   *           <entry key="Software">
   *             <entry key="Microsoft">
   *               <entry key="Windows">
   *                 <entry key="Name">
   *                   <value>Just a name</value>
   *                 </entry>
   *               </entry>
   *             </entry>
   *           </entry>
   *         </entry>
   *       </Registry>
   *     </entry>
   *   </results>
   * 
   *   // To find the value of the key called "name", here's how these methods can be used.
   *   // registry is a variable representing the payload
   *   var node = findRegistryNode(registry, "HKEY_LOCAL_MACHINE.Software.Microsoft");
   *   var name = findNodeValueWithAttribute(node, "Name");
   *********************************************/
  findRegistryNode: function(currNode, regName){
      var node = currNode;
      var names = regName.split(".");

      for (var i=0; i<names.length; i++) {
          node = this.findNodeWithAttribute(node, names[i]);
          if (!node)
              return null;
      }

      return node;
  },

  findNodeWithAttribute: function(currNode, attrName) {
      if (JSUtil.nil(currNode))
          return "";

      var nodeArray = g_array_util.ensureArray(currNode.entry);
      for (var i=0; i<nodeArray.length; i++)
          if (nodeArray[i]['@key'] == attrName)
              return nodeArray[i];

      return null;
  },

  findNodeValueWithAttribute: function(currNode, attrName) {
      if (JSUtil.nil(currNode))
          return "";

      var nodeArray = g_array_util.ensureArray(currNode.entry);

      for (var i=0; i<nodeArray.length; i++) {  
  		
          if (nodeArray[i]['@key'] == attrName) {         
              // WMI - expected output a non-null json object { '@type': "xxx", '#text': "returned value" }
              if (JSUtil.notNil(nodeArray[i].value) && JSUtil.notNil(nodeArray[i].value['#text']))             
                  //return the #text field, ignoring the @type field value
                  return nodeArray[i].value['#text']; 
              else                
                  // Powershell - expected output
                  return nodeArray[i].value;		  
  	    } // end if 

      } // end for

      return "";
  },
  
  type: "WindowsInstalledSoftwareLegacy"
};

Sys ID

7e2de2f2733300102535b7385ef6a7a7

Offical Documentation

Official Docs: