class Inspec::Resources::WindowsPkg

Determines the installed packages on Windows using the Windows package registry entries. @see: blogs.technet.com/b/heyscriptingguy/archive/2013/11/15/use-powershell-to-find-installed-software.aspx

Public Instance Methods

info(package_name) click to toggle source
# File lib/inspec/resources/package.rb, line 302
    def info(package_name)
      search_paths = [
        'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
        'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
      ]

      # add 64 bit search paths
      if inspec.os.arch == "x86_64"
        search_paths << 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
        search_paths << 'HKCU:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
      end

      # Find the package
      cmd = inspec.command <<-EOF.gsub(/^\s*/, "")
        Get-ItemProperty (@("#{search_paths.join('", "')}") | Where-Object { Test-Path $_ }) |
        Where-Object { $_.DisplayName -like "#{package_name}" -or $_.PSChildName -like "#{package_name}" } |
        Select-Object -Property DisplayName,DisplayVersion | ConvertTo-Json
      EOF

      # We cannot rely on `exit_status` since PowerShell always exits 0 from the
      # above command. Instead, if no package is found the output of the command
      # will be `''` so we can use that to return `{}` to match the behavior of
      # other package managers.
      return {} if cmd.stdout == ""

      begin
        package = JSON.parse(cmd.stdout)
      rescue JSON::ParserError => e
        raise Inspec::Exceptions::ResourceFailed,
              "Failed to parse JSON from PowerShell. Error: #{e}"
      end

      # What if we match multiple packages?  just pick the first one for now.
      package = package[0] if package.is_a?(Array)

      {
        name: package["DisplayName"],
        installed: true,
        version: package["DisplayVersion"],
        type: "windows",
      }
    end