Do you have a scripting-related question or problem? You can send your question or problem to [email protected]
I want to use Windows Management Instrumentation (WMI) to read the security settings on files and folders. I've seen numerous examples of such scripts, but they all fall short of displaying the permissions in a readable format. How can I use WMI to obtain and display individual permission settings?
You use the WMI Security Provider to dissect a file's or folder's security settings. Specifically, you use four classes defined in the WMI root\cimv2 namespace:
- Win32_LogicalFileSecuritySetting. The Win32_LogicalFileSecuritySetting class represents the security settings for a file or folder.
- Win32_SecurityDescriptor. The Win32_SecurityDescriptor class represents the file's or folder's Security Descriptor (SD).
- Win32_ACE. The Win32_ACE class represents the access control entries (ACEs) in the SD's discretionary ACL (DACL) and system ACL (SACL).
- Win32_Trustee. The Win32_Trustee class represents the trustee to which an ACE applies.
The process of unraveling an SD involves the following steps:
- Connect to the WMI Service on the target computer.
- Fetch the target file's or folder's security settings by using the Win32_LogicalFileSecuritySetting class.
- Retrieve the file's or folder's SD from the security settings by using the Win32_LogicalFileSecuritySetting class's GetSecurityDescriptor method.
- Examine the values in the file's or folder's SD.
The script WMISecurity.vbs performs these four steps to read and display the security settings that have been applied to the C:\windows folder on a computer named dell610. Listing 1 and Listing 2, page 6, show excerpts from this script. You can find the complete script in the Code Library on the Windows Scripting Solutions Web site (http://www.winscriptingsolutions.com). Although WMISecurity.vbs is long, the exercise of reading an SD is more tedious than difficult.
The first 82 lines in the script set up the script's variables. The four variables that warrant explanation are CONTROL_FLAGS, ACCESS_MASK, ACE_FLAGS, and ACE_TYPE. These Dictionary objects determine which bits are set in the SD's ControlFlags property and in each ACE's AccessMask, AceFlags, and AceType properties, respectively. As the excerpt in Listing 1 shows, the script defines these dictionary objects.
The Win32_SecurityDescriptor class's ControlFlags property and the Win32_ACE class's AccessMask, AceFlags, and AceType properties represent the gory details of an SD. All four properties are integer values, and each bit in each integer represents a unique setting. This type of integer is commonly called a bit field or bit flag. Because each bit represents a different setting, simply displaying the integer values of the four properties is of little use. You must examine each bit in each property to understand the SD's details. Dictionary objects provide an efficient structure to do so, as you'll soon see.
After the first 82 lines, WMISecurity.vbs starts to implement the four steps. Here's a detailed look at those steps:
Steps 1 and 2. To connect to the WMI Service on the target computer, the script uses a standard WMI connection string (i.e., a moniker). Immediately following the connection, the script fetches the target folder's security settings by using the Get method of the SWbemServices object (which the wmiServices variable represents). This method retrieves an instance of the class you specify as Get's first parameter. In this case, Get retrieves an instance of the Win32_LogicalFileSecuritySetting class, which represents the security settings for the target folder. Using the reference (i.e., wmiSecuritySettings) to the folder's Win32_LogicalFileSecuritySetting instance, the script displays the values of the six Win32_LogicalFileSecuritySetting class properties.
Note that ControlFlags is one of the six properties. ControlFlags provides important information about the SD, such as the SD's inheritance flags and whether it contains a DACL and SACL. At this point, the script could examine the bits in ControlFlags. However, the Win32_SecurityDescriptor provides an identical ControlFlags property that the script will later examine.
Step 3. The script calls the Win32_LogicalFileSecuritySetting class's GetSecurityDescriptor method, as the code at callout A in Listing 2 shows. GetSecurityDescriptor accepts one parameter: the variable to which you want to assign the folder's SD. This type of parameter passing is commonly called pass by reference. In this case, I've passed the wmiSecurityDescriptor variable to the GetSecurityDescriptor method. The method initializes this variable with an instance of Win32_SecurityDescriptor. The Win32_SecurityDescriptor instance provides five properties:
- ControlFlags. The Win32_SecurityDescriptor class's ControlFlags property is identical to the Win32_LogicalFileSecuritySetting class's ControlFlags property, which I described earlier.
- DACL. The DACL property is an array of Win32_ACE objects that make up the SD's DACL. Each Win32_ACE in the DACL identifies a trustee and the permissions granted or denied to the trustee.
- Group. The Group property is the SD's group owner in the form of a Win32_Trustee object.
- Owner. The Owner property is the SD's owner in the form of a Win32_Trustee object.
- SACL. The SACL property is an array of Win32_ACE objects that make up the SD's SACL. Each Win32_ACE in the SACL identifies a trustee and the audit permissions applied to the trustee.
Because the SD's owner is an instance of the Win32_Trustee class, the script sets a reference (i.e., the wmiOwner variable) to that class's Owner property. The script then displays the SD owner's name, SID, and domain.
Step 4. The last step is to examine the five bit fields. As the code at callout B in Listing 2 shows, the script begins by examining the first bit field—the Win32_SecurityDescriptor's ControlFlags property. Recall that each bit in ControlFlags represents a unique setting. To examine each bit, the script uses the CONTROL_FLAGS Dictionary object.
A Dictionary object is simply a list of items. Each item consists of two parts: a key and a value. Table 1 lists the key-value pairs in the CONTROL_FLAGS Dictionary object. You use the Dictionary object's key to retrieve a specific value from the Dictionary object, much as you use a numeric index to retrieve an element in an array. However, unlike an array in which the index is a fixed number, the Dictionary object's keys can be numbers or strings. This feature makes Dictionary objects particularly well suited for reading files' and folders' security settings because you can store friendly names in addition to the values used to perform the bitwise comparisons. You use the friendly name to reference the bit value (i.e., position) you want to compare with the target bit field property and, if the bitwise comparison is true, display the friendly name. Let's look at this capability in action.
The code at callout B begins by setting the blnFirstValue variable to True. The script uses this value to help format output inside the For Each...Next statement. The For Each...Next loop uses the Dictionary object's Keys method to loop through all the keys in CONTROL_FLAGS. During each loop iteration, an If...Then...Else statement performs a bitwise comparison between the current CONTROL_FLAGS key's value and the ControlFlags property's value. If both identically positioned bits are set (i.e., have a value of 1), the If...Then...Else statement evaluates to True and the script displays the key's friendly name.
Next, the script uses ControlFlags a second time to test the SE_DACL_PRESENT bit, as the code at callout C in Listing 2 shows. If the SE_DACL_PRESENT bit is set, the SD contains a DACL, in which case the body of the If...Then...Else statement executes. The script initializes an array variable named arrDacl with the array of Win32_ACE objects that make up the folder's DACL. A For Each...Next statement iterates through the array. For each Win32_ACE in the arrDacl array, the following actions take place:
- The script retrieves and displays the Win32_ACE Trustee property. The code that the script uses to accomplish these tasks is similar to the code that the script uses to retrieve and display the SD's Owner property.
- The script uses the ACE_TYPE Dictionary object to map the Win32_ACE AceType property's value to a friendly name and display that name.
- The script uses the ACCESS_MASK Dictionary object to examine and display the Win32_ACE AccessMask property's bit field.
- The script uses the ACE_FLAGS Dictionary object to examine and display the Win32_ACE AceFlags property's bit field.
After the script examines and displays all the Win32_ACE objects in the folder's DACL, the script moves on to the SACL (not shown in Listing 2). The script performs the same actions on the SACL as it did on the DACL.