Working with Dictionaries
I don't know about you, but I usually think about using a dictionary to check the spelling of a word or to find a definition. In Windows Scripting, however, a dictionary has nothing to do with either of these concepts, although its use is just as important, perhaps more so. So what is a dictionary in our context? Well, a dictionary is kind of like an array, only easier to work with. It is a place to hold data. Just like an array can be used to hold data in a convenient place for use within the script, a dictionary also holds data. A dictionary works like a single dimension array. You can store only one column's worth of data in your dictionary.
Because enterprise scripts have to get information from other places (a command-line argument, a text file, or an Active Directory Services Interface [ADSI] query), it is convenient to store the information locally to avoid repeated calls to the outside source. Once the information is local, you can manipulate it into a more manageable form. In Chapter 4, "Working with Arrays," and earlier in this chapter, you looked at using arrays to store information locally. In certain situations, you can use a dictionary to perform the same type of activitythat is, for convenience, you can temporarily store working information in the Dictionary object.
As mentioned earlier, the dictionary works like an array in that each item in the dictionary is stored with its associated key. The key is used to identify the value we want to store, or retrieve, from the dictionary. With an array, we used the index number to retrieve the data. In the dictionary, we use the key. In a dictionary, we have a key and an item. The dictionary offers a couple of advantages over arrays. The first advantage is that you can retrieve any specific item from the dictionary simply by knowing the key, whereas with an array, you need to know the array index number. The second advantage is that a dictionary doesn't require any specific size configuration. With an array, you must either know its exact size or resize it.
Understanding the Dictionary Object
To use the VBScript dictionary, you need to first create it. (In technical terms, the dictionary is a Microsoft Component Object Model (COM) object and gets created via the CreateObject method.) The basic syntax for this is seen below:
Set objDictionary = CreateObject("scripting.dictionary")
 |
Q. | What are the advantages of using a dictionary rather than an array?
| A. | The dictionary enables retrieval of specific items from the dictionary without knowledge of the index number. In addition, the dictionary is automatically dynamically sized. | Q. | Because a dictionary is a COM object, how does it get instantiated?
| A. | A dictionary gets instantiated by using the CreateObject command. |
|
|
Compare Mode
The dictionary enables us to configure only one property: the compare mode. This is actually part of what makes the dictionary easy to use (the lack of configurable properties, not the compare mode itself). In reality, most of the time, the default compare mode (which is binary mode) is fine. Compare mode enables you to configure the way in which the dictionary compares items when used to search for previously added items. The other compare mode (besides binary) is text mode. Text mode is case-insensitive. In binary mode, server1 and Server1 are two different computers, whereas in text mode they would be the same machine. It is important to remain aware of these differences.
Note  | If you want to change the compare mode from binary to text mode, you must do this before you add any information to the dictionary. |
Adding Items to the Dictionary
After you create the dictionary, you add items to it. (It's basically useless without information, just like a printed dictionary containing only blank pages.) So how do you add information to the dictionary? You guessed itusing the Add method. In this example, we are using a number for the key. This is perfectly acceptable, and we can easily walk through the dictionary via For ... Next. The advantage of the dictionary in the BasicDictionary.vbs script is that it is automatically dynamic.
BasicDictionary.vbs
Option Explicit
Dim objDictionary, i
Set objDictionary = CreateObject("scripting.dictionary")
objDictionary.Add 1, "server1"
objDictionary.Add 2, "server2"
objDictionary.Add 3, "server3"
objDictionary.Add 4, "server4"
For i = 1 To 4
WScript.Echo objDictionary.item (i)
next
In the BasicDictionary.vbs script, you first create the dictionary and assign it to the variable objDictionary. You use this variable because you use the CreateObject command to make a dictionary, and the name objDictionary tells us that the variable is an object that is a dictionary. You then add one item to the dictionary, called server1, which is assigned to a key called 1. From this code, you can see the syntax is add key item, as illustrated here:
Command | Key | Item |
---|
objDictionary.Add | 1 | Server1 |
Counting with the count
1. | Open the BasicDictionary.vbs script in Notepad or your favorite script editor. Save the file as YourNameBasicDictionaryCount.vbs.
| 2. | On the line that reads For i = 1 To 4, change the number 4 to be the count of items in the dictionary. To do this, we use the Count property, as seen below:
For i = 1 To objDictionary.count
| 3. | Save and run the script. You will see it behaves exactly as the BasicDictionary.vbs script. The advantage of this is that we can now add other items to the dictionary and echo out the items in the collection without having to change the for i = 1 To 4 line of code each time.
| 4. | Under the For...Next loop, add server5 to the dictionary. Use 5 for the key value. The line of code must be typed exactly:
objDictionary.Add "5", "Server5"
| 5. | Save and run the script. You will notice server5 is not printed out in the output. This is because we added it after the Output section of the script. To verify the item was added properly to the dictionary, echo out the count of the dictionary, as seen below:
WScript.Echo "The count after adding key ""5"" with ""server5""" & _
" to the dictionary is " & objDictionary.Count
| 6. | Add another For...Next loop after the WScript.Echo line. You can copy the one already used by the script. It looks like the code below.
For i = 1 To objDictionary.count
WScript.Echo objDictionary.item (i)
Next
| 7. | Save and run your script. You will notice the output does not include server5. The output is seen below:
server1
server2
server3
server4
The count after adding key "5" with "server5" to the dictionary is 5
server1
server2
server3
server4
Exit code: 0 , 0000h
| 8. | Notice there is a blank line after the second printout, right before the exit code. (Depending on how your script editor is configured, you may or may not have an exit code printed out at the conclusion of your script.) Query the Count property again to see if you can find any change. My code looks like the following:
WScript.Echo "The count after using the second for ... next loop "&_
"Is " & objDictionary.Count
| 9. | The count has now incremented to 6. Let's see what is going on with our new server. Echo out the type name of objDictionary.item("5") by using the TypeName function.
WScript.Echo "Item ""5"" is a " & TypeName(objdictionary.Item("5"))
| 10. | Run the script. It reports that the item associated with "5" is a string.
| 11. | Modify the echo line to print out the type name of the item associated with 6. This is seen below:
WScript.Echo "Item 6 is a " & TypeName(objdictionary.Item(6))
| 12. | Notice that the item associated with key 6 is empty. What happened is that the dictionary added an empty item to the dictionary. The question at this point is why? To find out, we will need to work with the keys. We will do this in the next procedure, " The key to keys."
|
Important  | There are many times when we need to include a quotation mark inside an output string. To do this, we need to "escape" the character. If I use only one quotation mark, then the script runtime engine will think I am done with my string value and interpret the next character as a command, which nearly always results in errors. In the Counting the count procedure, we escape the key value with two sets of quotation marks. What really looks strange is the three quotation marks in a row at the end of the first line. The extra quotation character is required to end the first selection of quotes. |
The key to keys
1. | Open BasicDictionaryCount.vbs and save it as YourNameBasicDictionaryKEYS.vbs. You can use Notepad or your favorite script editor to do this.
| 2. | To work with the keys, we will need to create an array of keys so we can walk through them. To do this, we need to first create two variables: aryKeys and key. This is seen below:
Dim aryKeys 'holds array of keys from keys method
Dim key 'an individual key in the array
| 3. | To get a collection of keys, we use the Keys method of the Dictionary object. Assign it to the aryKeys variable as seen below:
aryKeys = objDictionary.Keys
| 4. | To confirm we have an array of keys, let's use the vartype function to echo out the data type of aryKeys. This is seen below:
WScript.Echo "aryKeys is " & vartype(aryKeys)
| 5. | vartype returns a number. The number for aryKeys is 8204. Open the \My Documents\Microsoft Press\VBScriptSBS\Resources\Script56.chm file and find the article associated with vartype. You will see that these values can be additive. Although these varitype numbers are not listed specifically, they can be determined by adding 8192 (which is an array) to 12 (which is a variant). This tells us that aryKeys is an array of variants.
| 6. | Now use vartype to print out the data type of each key stored in our array of keys. Use For Each to do this. My code looks like the following:
For Each key in aryKeys
WScript.Echo "key " & key & " is a " & vartype(key)
Next
| 7. | Examine the output produced by this script. Look up the vartype of each key in the Script56.chm file. I have copied the output below:
server1
server2
server3
server4
The count after adding key "5" with "server5" to the dictionary is 5
server1
server2
server3
server4
The count after using the second for ... next loop Is 6
Item "5" is a String
Item 6 is a Empty
aryKeys is 8204
key 1 is a 2
key 2 is a 2
key 3 is a 2
key 4 is a 2
key 5 is a 8
key 5 is a 3
key 6 is a 2
| 8. | Notice we have two keys listed for 5. The first is a string. The second is a long. The first four keys are all integers.
| 9. | Notice there is also a key 6. This one is an integer and not a long. This one was added when we tried to see the data type of the item associated with the newly added item that had increased the count. Because we did not know the key, we assumed it would be 6. However, because there was not a number five in use, that one was added first. Then by querying a key that did not exist for its type name, we created an additional key in the dictionary.
| 10. | Compare your results with \My Documents\Microsoft Press\VBScriptSBS\ch05\BasicDictionaryKeys.vbs.
|
Caution  | When we added key 5, we enclosed the number 5 with quotation marks. This caused the script engine to interpret it as a string, the letter five, instead of as an integer, the number five. When we used the For...Next command to walk through the items in the dictionary, we were specifying the keys that were integers. However, because we went to the count of the dictionary, we printed out five items associated with the keys that were integers. Because the number five did not exist, the Dictionary object added it automatically. Please note: It is perfectly acceptable to have a mixture of integers and strings as key items in a dictionary; however, it is very confusing. |
Removing items from the dictionary
1. | Open the \My Documents\Microsoft Press\VBScriptSBS\ch05\Basic DictionaryKeys.vbs script in Notepad or your favorite editor and save it as YourNameBasicDictionaryRemoveKeys.vbs.
| 2. | At the bottom of the script, echo out the count of the dictionary, so we know what we are working with. My code looks like the following:
WScript.Echo "before we remove key 6, the count is: " & objDictionary.Count
| 3. | Now use the Remove method to remove key 6. Echo out a message telling the user you are going to remove the key. Concatenate the lines with & and call the Remove method. This code looks like the following:
WScript.Echo "removing key 6 ..." & objDictionary.Remove(6)
| 4. | Confirm the removal of key 6 by using the count again. This line of code looks like the following:
WScript.Echo "After removal of 6, the count is: " & objDictionary.Count
| 5. | Now we want to add "server5" to the item of key 5 (the integer) and remove key 5 (the string). To do this, however, we want keep the data stored in item("5"). Declare a variable strItem to hold the data in item("5"). It looks like this:
Dim strItem 'holds data stored in key "5"
| 6. | At the bottom of your script, use strItem to hold the data stored in item("5"). The code for this looks like:
strItem = objDictionary.Item("5")
| 7. | Now remove both key("5") and key(5). Use the following code to remove these keys:
objDictionary.Remove("5")
objDictionary.Remove(5)
| 8. | Verify the two keys were removed by checking the count. My code looks like the following:
WScript.Echo "after removing two keys, count is: " & objDictionary.Count
|
Adding items back to the dictionary
1. | Open \My Documents\Microsoft Press\VBScriptSBS\ch05\BasicDictionaryRemoveKeys.vbs and save it as YourNameBasicDictionaryAddKeys.vbs. Use Notepad or your favorite script editor.
| 2. | To add data back to the dictionary, we use the Add method. However, because we have removed several items and added back some other items, we may not be sure of what the last key in the dictionary is. To avoid creating an error, let's use the count to create the proper key. We get the count, which tells us how many items are in the dictionary, then we add one to it. This gives us the next number in the dictionary. To do this, use the following code:
objDictionary.Add objdictionary.Count + 1,strItem
| 3. | Verify the data was added by checking the count. I used the following code to do this:
WScript.Echo "after adding back, the count is: " & objDictionary.count
| 4. | Print out each item in the dictionary. Use For...Next and go to the count of the dictionary. Use i to indicate the key value and use it with the Item method to retrieve the item associated with the key. This code is seen below:
For i = 1 To objDictionary.Count
WScript.Echo objDictionary.Item(i)
Next
| 5. | To avoid adding empty key values to the dictionary, as we did in the original script, use the Exists method of the Dictionary object to verify the existence of the key prior to echoing it out. Use an If...Then statement to do this. The following code shows the completed structureincluding the For...Next loop added in step 4.
For i = 1 To objDictionary.Count
If objDictionary.exists(i) Then
WScript.Echo objDictionary.Item(i)
End If
Next
| 6. | You should see all five servers printed out at the bottom of the output. If you do not, compare your script with BasicDictionaryAddKeys.vbs.
|
|