Welcome to Your Nightmare

Audit the software on users' machines with this month's handy script.

Your phone rings. It’s one of your users—the user who has come to be known as The Hurricane due to his capacity to leave destruction in his wake. “I can’t get my e-mail!” “I can’t print!” “My computer is locked up!”

You arrive at Hurricane’s desk and begin looking for the problem. Usually, Hurricane offers little or no help—providing completely useless clues such as, “It just died,” or “It’s too slow.” Today, however, Hurricane is feeling generous.

“I was installing The Bridges of Madison County screensaver…” A cold chill runs through you. You begin to shake.

It’s OK. We’ve all been there. “Hi, my name is Chris, and my users are idiots.” (Chorus) “Hi, Chris!” There may still be hope. Perhaps you can write a script to remotely connect to users’ machines and enumerate installed software. If you schedule it to run regularly, you can review the listing for any new (and probably unauthorized) software and get it removed before it’s too late!

<?xml version="1.0" ?>
<package>
<comment>
ListApps.wsf
This script enumerates the MSI installed applications as
well as all installed hotfixes.
</comment>

  <job>
    <runtime>
    <description>

    This script uses WMI to connect to the local or
    remote computer and return a list of installed
    applications and hotfixes
    </description>

    <example>
    C:\cscript ListApps.wsf /Target:value /File:value
    </example>

    <named
    name=
"Target"
    helpstring="The name of the target computer"
    type="string"
    required="true"
    />

    <named
    name=
"File"
    helpstring="The name of the text file to store the data"
    type="string"
    required="true"
    />
    </runtime>

    <object id="objFSO" progid="Scripting.FileSystemObject"/>
    <script language=
"VBScript">
    <![CDATA[
    Option Explicit
    CONST ForAppending=8
    Dim objFile, objWMI, colSoftware, clsSoftware, colHotFixes,
       clsHotFix, strComputer, strFile
    strComputer = WScript.Arguments.Named.Item("Target")
    strFile=WScript.Arguments.Named.Item("File")
    Set objFile = objFSO.OpenTextFile(strFile,
      ForAppending, True)
    Set objWMI =
      GetObject("winmgmts:{impersonationLevel=impersonate}!\\"
      & strComputer & "\root\cimv2")
    Set colSoftware = objWMI.ExecQuery(
      "Select * from Win32_Product")

    objFile.WriteLine "Computer Name: " & strComputer
    ' Get the installed software data
    For Each clsSoftware in colSoftware
      objFile.WriteLine "Caption: " & clsSoftware.Caption
      objFile.WriteLine "Description: "
        & clsSoftware.Description
      objFile.WriteLine "Identifying Number: "
        & clsSoftware.IdentifyingNumber
      objFile.WriteLine "Install Date: "
        & clsSoftware.InstallDate2
      objFile.WriteLine "Location: "
        & clsSoftware.InstallLocation
      objFile.WriteLine "Install State: "
        & clsSoftware.InstallState
      objFile.WriteLine "Name: " & clsSoftware.Name
      objFile.WriteLine "Package Cache: "
        & clsSoftware.PackageCache
      objFile.WriteLine "SKU Number: " & clsSoftware.SKUNumber
      objFile.WriteLine "Vendor: " & clsSoftware.Vendor
      objFile.WriteLine "Version: " & clsSoftware.Version
      objFile.WriteLine
    Next

    objFile.WriteLine "Hotfixes:"

    Set colHotFixes = objWMI.ExecQuery("Select * from       Win32_QuickFixEngineering")

    ' Get the installed hotfixes
    For Each clsHotFix in colHotFixes
      objFile.WriteLine "Description: " & clsHotFix.Description
      objFile.WriteLine "ID: " & clsHotFix.HotFixID
      objFile.WriteLine "Installation Date: "
        & clsHotFix.InstallDate
      objFile.WriteLine " Installed By: "
        & clsHotFix.InstalledBy
    Next

    objFile.WriteLine

    objFile.Close

    ]]>
    </script>
  </job>
</package>

Bonus!
Did you notice? I gave you a bonus in this script. That’s right! In addition to listing all software installed using the Windows Installer, this script also enumerates all installed hotfixes. This means that while you’re reviewing the listings to see if any of your users installed “Dark Age of Camelot,” you’ll also be able to ensure that they’re completely up to date with any required hot fixes.

A Minor Limitation
While this script is very powerful, it does have one significant weakness: It’ll only itemize software installed using the Windows Installer. Granted, most contemporary software uses Windows Installer, but it’s something to keep in mind. When I ran this script on my notebook computer and compared it to the listing in my “Add/Remove Programs” applet, the script didn’t show five applications.

Another Bonus?
Since I began this series on using WMI to perform administrative tasks, I’ve received a few e-mails from people having difficulty running them in different environments (I use XP). For that reason, I’m giving you another bonus this month: A diagnostic script that returns the version numbers of the various scripting elements.

In the interest of space, I’ve written this as a .VBS script (complete with “standard” VBScript color coding, as opposed to the XML color coding I use in .WSF scripts). If you wish, you can put this in a .WSF file, too.

' GetVersions.vbs
' This script writes the version number of the individual
' scripting components to the screen. It can also be modified
' to write the information to a file and/or run on multiple
'
computers
Dim objWMI, colWMISettings, clsWMISetting, objShell,
strADSIVersion

  ' Display WSH version
  WScript.Echo "WSH Version: " & WScript.Version

  ' Display WMI version
  Set objWMI = GetObject(
    "winmgmts:{impersonationLevel=impersonate}!\\
    computername\root\cimv2")
  Set colWMISettings = objWMI.ExecQuery("Select * from
    Win32_WMISetting")

  For Each clsWMISetting in colWMISettings
   Wscript.Echo "WMI Version: " & clsWMISetting.BuildVersion
 Next

  ' Display ADSI version
 Set objShell = CreateObject("WScript.Shell")
 strADSIVersion = objShell.RegRead(
   "HKLM\SOFTWARE\ Microsoft\Active Setup\
   Installed Components\
   {E92B03AB-B707-11d2-9CBD-0000F87A369E}\Version")
 
If strADSIVersion = vbEmpty Then
 
strADSIVersion = objShell.RegRead(
   "HKLM\SOFTWARE\Microsoft\ ADs\Providers\LDAP\")

  If strADSIVersion = vbEmpty Then
  strADSIVersion = "ADSI is not installed."
  Else
  strADSIVersion = "2.0"
End If
End If
WScript.Echo
"ADSI Version: " & strADSIVersion
Set objWMI=Nothing
Set colWMISettings=Nothing
Set clsWMISetting=Nothing
Set objShell=Nothing

Compare the results of this script with the list below. It outlines the recommended minimum version numbers for each scripting element.

  • WSH (Win9x, NT 4/2000/XP)—V5.6
  • WMI (Win9x, NT 4/2000)—1085.0005, (WinXP)—2600.0000
  • ADSI (Win9x, NT 4/2000/XP)—5,0,00,0

If any component on your system is older than the ones on this list, download the most recent version from the appropriate Microsoft site below.

Featured