I want to query the PCs on our network for the status of the Symantec Norton Antivirus software that runs on them. I want to find out whether Norton Antivirus is present and (if possible) the version of the current signature. Can I use a script to do this, and if so, do you have an example that I could use as a template?
I imagine that Symantec has enterprise tools that you can use to collect the information you want, and I know that tools such as Microsoft Systems Management Server (SMS) can collect software information. That said, yes, you can use a script to collect the information. And I can provide several routines that you can use as templates for collecting software information about Norton Antivirus.
Two of the code samples that I provide demonstrate alternative approaches for detecting whether a software package (in this case, Norton Antivirus 2005) is installed. The two other code samples demonstrate approaches for detecting and reporting software-configuration details (in this case, the versions of the installed antivirus signatures). You can customize these scripts to collect all kinds of information about installed software. I show two approaches for collecting each piece of information because in each case, the first (and most obvious) approach is processor- intensive and long-running. These techniques provide a baseline that you can use to construct alternative, more efficient approaches to obtaining similar information about other software packages. You can download all the scripts from the Windows Scripting Solutions Web site. Go to http://www.windowsitpro.com/windowsscripting, enter 45820 in the InstantDoc ID text box, then click the 45820.zip hotlink.
Detecting the software. The first example for detecting software shows how to use the Windows Management Instrumentation (WMI) Win32_Product class to determine whether Norton Antivirus is installed and, if so, which version is installed. To take this approach, use the Method1_SoftwareDetect.vbs script. This script connects to the WMI CIMv2 namespace, then queries the Win32_Product class for any name that starts with Norton Antivirus. The advantage to this approach is the ease and consistency with which the Win32_Product class can obtain all kinds of information about installed software. However, the approach does have some notable weaknesses.
First, searching in this way requires the use of the WMI Query Language (WQL) WHERE clause's LIKE operator. This operator is supported only on Windows Server 2003 and Windows XP. Therefore, you can't run this query on a computer that runs any earlier version of Windows. An alternative approach is to use the equals (=) operator and search for an exact match of the software name. However, that approach won't detect Norton Antivirus versions that don't exactly match your search string.
Second, the search can take a long time to complete if the Win32_Product class must enumerate a lot of instances to build the collection. In my tests, running the code on the local computer with about 40 software packages installed took upwards of 30 seconds to complete. Even optimizing the query by setting the WBEM_FLAG_FORWARD_ONLY and WBEM_FLAG_RETURN_IMMEDIATELY flags on the query doesn't help much. Setting the former flag makes the query semisynchronous but means that you can't determine how many results were returned from the query until after you've iterated the returned collection. When you use the WBEM_FLAG_FORWARD_ONLY flag, you can't call the Count property (a property of SWbemObjectSet) from the returned collection, as the code in Listing 1 does. Another option would be to optimize the query by using both flags, then set a Boolean variable to True if you enter the For Each loop, as the code in Listing 2 does. However, even with these optimizations, the script took more than 20 seconds to complete on my test systems. Also, the Win32_Product WMI class applies only for products that the Windows Installer service has installed and won't detect products installed by other means.
For a faster and more platform-compatible way to determine whether software is installed, use the Method2_SoftwareDetect.vbs script. This script uses the WMI Registry Provider (StdRegProv) class and two of its methods: EnumKeys and GetStringValue. The script works on any Windows platform that supports WMI and completes much fasterâ€”10 times faster, on my test systemsâ€”than the first script. Additionally, the script can detect programs that weren't installed by Windows Installer but that are listed in the Control Panel Add/Remove Programs applet.
Obtaining configuration information. The first step to building a script to obtain software configuration information is inspecting how a program stores specific configuration information. Norton Antivirus stores virus-definition information in the file system and in the registry. The file system location is typically %commonprogramfiles%\Symantec Shared\VirusDefs. The signature-file update process creates a subfolder for each set of signature files; each subfolder's name includes a prefix that specifies the date of the signature-file download and a three-digit extension that makes the signature-download name unique. For example, the antivirus signature-download folder from February 3, 2005, is named 20050203.008.
The first script for detecting the version of installed antivirus signatures, Method1_SoftwareConfigDetect.vbs, shows how to use the file-system information to display information about the corresponding signature folders. This script uses the WSHShell object's ExpandEnvironmentStrings method to build a path to the location of the Norton Antivirus signature folders. The script then uses the FolderExists method of the FileSystemObject, which is part of the Windows Script Host (WSH) script runtime, to determine whether %commonprogramfiles%\Symantec Shared\VirusDefs exists. When the folder does exist, the script passes the folder path to the WMI Win32_Directory class in a query expression that searches for any folder beginning with 200. This query will list all signature folders installed from the year 2000 to the year 2009. (By the year 2009, I'm guessing that we'll all be using different approaches for getting at this informationâ€”or we'll be doing something else for a living.) Be warned: Running the Win32_Directory query takes even longer than enumerating the Win32_Product class. On my test systems, the Win32_Directory query took more than 40 seconds to complete.
A faster approach for getting at the folder data would be to use the FileSystemObject instead of Win32_Directory. However, my alternative script, Method2_SoftwareConfigDetect.vbs, sticks with WMI Registry Provider but checks the registry, rather than the file system, for the signature data. The clear advantage of this approach is how fast the data is returned. On my test systems, returning the most recent virus signature and other version information was 80 times as fast as the script that enumerates the Win32_Directory class (the process took about 0.5 second). To make the display even faster (twice as fast, on my test systems), you can simply return the antivirus-signature version information for the NAV_NAVW32 registry entry, as the code in Listing 3 shows. You'll find the code for that approach in the Method3_SoftwareConfigDetect.vbs script.
With these script examplesâ€”specifically Method2_SoftwareDetect.vbs and Method3_SoftwareConfig-Detect.vbsâ€”you should be able to assemble a script to determine whether Norton Antivirus is installed and what the antivirus-signature version is on each of your network computers. I suggest that you add more error handling to the scripts and make sure that a computer is available on the network before you attempt to connect to it via WMI. (For more information about the latter task, see the article "Remote Administration with WMI," February 2003, InstantDoc ID 37596.)