Mr. Script

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.

comments powered by Disqus

Reader Comments:

Wed, Jul 6, 2005 Jacob Smith Walla Walla, Washington

Chris,

I dig your scripting column in Redmond Magazine.

I just stumbled onto this old column while Goolgling. The bonus script that returns the version numbers of the various scripting elements is real handy.

How do I get the latest version of WSH distrubuted? I have looked for an MSI package that I can send out with Group Policy, but have yet to find one. Is there a better way?

Sat, Dec 21, 2002 Bob Forys Charleston SC

Please read and implement the observations of those that bothered to post the thoughts. Most all are valid points and questions that need to be addressed. I have used a similar script with some interesting and alarming results. Software enumneration registry reads by scripts are absolutely neccessary[-from Gary Williams' post].

Sat, Dec 14, 2002 Anonymous Anonymous

yes chris, some of us would still like you to tell us how to begin the scripting process. Command line is easy enough to find, then what? thanks....

Tue, Nov 19, 2002 Gary Williams St. Louis

Your 'Minor Limitation' is not so minor. I've seen software installed using MSI that won't be enumerated using this method. It's much better to have the script read the registry to get installed software.

Thu, Nov 14, 2002 Lou New Jersey

I modified the installdat2 var to installdate and the app ran normally.

What are others using as editors for wsf and wsh files?

Thu, Oct 31, 2002 Anonymous Anonymous

Very funny, we all laughed and thought, wow, its almost how we feel.

Mon, Oct 28, 2002 Miles Texas

I never thought this could be true until it happened to me. It came along with identity theft, DOService, vandalism, and phone intrusion... 'Script Kiddies, escapees from the local 'Get a Life' Support Group, and terrorism that leaked its way into the physical as well as the Cyber realm.

In fact it is still going on and no one will believe me except computer Literate people. What good is a Geek in a gunfight ???

I hope you would feel free to respond with any advice. I could use it.

Thanks.

Thu, Oct 24, 2002 Anonymous Anonymous

I keep getting an error
Object doesn't support this property or method: 'InstallDate2'
Code 800A01B6

Mon, Oct 21, 2002 Anonymous Anonymous

Looks good - I'll try it and if I really like it I'll set it up to read a list of machine names. Getting the software from one computer isn't super helpful.

Wed, Oct 16, 2002 Gerry Edmonton, AB

Why would I get an ActiveX error on GetObject?

Wed, Oct 16, 2002 Anonymous Anonymous

good

Wed, Oct 16, 2002 Chris Grotkowski Edmonton, AB

Good article - I am going to try these scripts out and see what happens. Thanks for the info!!!

Tue, Oct 15, 2002 Anonymous Anonymous

Good Article

Add Your Comment Now:

Your Name:(optional)
Your Email:(optional)
Your Location:(optional)
Comment:
Please type the letters/numbers you see above

Redmond Tech Watch

Sign up for our newsletter.

I agree to this site's Privacy Policy.