2008 Winter Scripting Games

Solution to Beginner VBScript Event 2: True Type

Event 2 Solution


VBScript solution to Event 2 in the 2008 Winter Scripting Games.

Solutions are also available for Windows PowerShell and Perl.

*

Event 2 – True Type

This event covered two separate areas of scripting. One was reading from the registry, the other was parsing a string. Let’s take a look at the final answer the Scripting Guys came up with:

Const HKEY_LOCAL_MACHINE = &H80000002
strComputer = "."

Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
 strComputer & "\root\default:StdRegProv")
 
strKeyPath = "Software\Microsoft\Windows NT\CurrentVersion\Fonts"
objReg.EnumValues HKEY_LOCAL_MACHINE, _
    strKeyPath,arrEntryNames

For Each entry in arrEntryNames
    iTotalFonts = iTotalFonts + 1
    If InStr(1, LCase(entry), "truetype") Then
        iTTFonts = iTTFonts + 1
        Wscript.Echo entry
    End If
Next
Wscript.Echo "TrueType:  " & iTTFonts
Wscript.Echo "Total:  " & iTotalFonts

There were two different ways you could have accomplished this event in VBScript. One way would be to use the WScript.Shell object to access the registry on the local machine. The other would be using WMI, in which case you could access the local registry or a registry on a remote machine. Either solution would be correct for this event, but we’ve chosen to show you the WMI solution.

We gave you a pretty big hint on this one in the Scripting Games Tips, where we basically showed you how to do this part (reading from the registry). Because of that we won’t go into great detail on that here, but we will walk through it quickly.

We start by declaring a constant named HKEY_LOCAL_MACHINE and assigning a hexadecimal value to that constant. We’ll use this constant to tell WMI that we want to connect to the HKEY_LOCAL_MACHINE hive of the registry. We also define a variable, strComputer, specifying which computer we want to work with. (The dot represents the local computer, but you could also enter the name of a remote computer.)

Next we call GetObject to connect to the root\default:StdRegProv WMI namespace. Always remember to use this namespace when you’re working with the registry rather than the root\cimv2 namespace, the namespace you typically use in WMI scripts.

Okay, that was all the preliminary stuff. Now we need to get specific and define the actual key in the registry we want to search. We said in the instructions for this event that you’d find everything you need in the HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts key of the registry, so we assign that path (minus the registry hive HKEY_LOCAL_MACHINE\) to the variable strKeyPath:

strKeyPath = "Software\Microsoft\Windows NT\CurrentVersion\Fonts"

Now we’re ready to read the values of this key. We do that by calling the EnumValues method:

objReg.EnumValues HKEY_LOCAL_MACHINE, _
    strKeyPath, arrEntryNames

We pass three parameters to EnumValues:

HKEY_LOCAL_MACHINE. The constant representing the registry hive we’re looking at.

strKeyPath. The variable containing the path to the key within that hive that we’re looking at.

arrEntryNames. An array that EnumValues will use to store the names of all the values in the given key.

The first thing you needed to do in this event was to display the names of the fonts, which correspond to the value names we just retrieved. So all we have to do is set up a For Each loop to loop through the array containing these values:

For Each entry in arrEntryNames

We also wanted to count the total number of fonts retrieved, so each time through the loop we add one to the counter iTotalFonts:

iTotalFonts = iTotalFonts + 1

Note: Couldn’t we have simply used the UBound function to return the highest index number in the array, then added 1 to get the total number of elements in the array? You know, kind of like this:

iTotalFonts = UBound(arrEntryNames) + 1

Yes. Why didn’t we? No particular reason. We need to loop through the array anyway, so adding the counter doesn’t hurt performance. This just shows there can be more than one way of doing the same thing, and it often doesn’t matter much which route you choose. Whichever is easiest for you is usually fine.

We said we wanted to echo back all the fonts, but that’s not entirely true. If you echoed back all the fonts, you didn’t receive any points for this event. What we really wanted were the true type fonts. It’s pretty obvious which fonts are the true type fonts; they all have (TrueType) appended to their names, like this:

Lucida Bright (TrueType)

That means that, in order to find the true type fonts, we simply need to find the fonts with “TrueType” in their names. We do that using the InStr function:

InStr(1, LCase(entry), "truetype")

The InStr function looks for a substring within a string and returns True if it finds the substring or False if it doesn’t. We pass InStr three parameters:

1 The character position within the string we’re going to search where we want to start our search. We’ve specified that we want to start at the beginning of the string, character position 1.

LCase(entry) This is the string we want to search. We’ve used the LCase function to say that we want to search for the lowercase version of the string.

“truetype” The string we’re searching for, in this case truetype.

Because InStr returns True or False, we can place the entire thing within an If statement:

If InStr(1, LCase(entry), "truetype") Then

If the string “truetype” is found in the registry value (the name of the font), we want to do two things. First, because we want to count the number of true type fonts we find, we increment the counter that keeps track of that number:

iTTFonts = iTTFonts + 1

Next we want to echo back the name of that font:

Wscript.Echo entry

Once we’ve looped through all the values we simply echo back the total number of fonts found and the total number of true type fonts found:

Wscript.Echo "TrueType:  " & iTTFonts
Wscript.Echo "Total:  " & iTotalFonts

And we’re done.


Top of pageTop of page