3.5 Core OS file system components providers


3.5 Core OS file system components providers

3.5.1 Disk quota provider

The Disk quota provider is made up of only one instance provider (see Table 3.42) supporting three classes. This provider is designed to expose information about quota settings configured on NTFS volumes.

Table 3.42: The Disk Quota Providers Capabilities

Provider Name

Provider Namespace

Class Provider

Instance Provider

Method Provider

Property Provider

Event Provider

Event Consumer Provider

Support Get

Support Put

Support Enumeration

Support Delete

Windows Server 2003

Windows XP

Windows 2000 Server

Windows 2000 Professional

Windows NT 4.0

Disk Quota Provider

DskQuotaProvider

Root/CIMV2

X

X

X

X

X

X

X

It supports one dynamic instance class and two association classes, as shown in Table 3.43.

Table 3.43: The Disk Quota Provider Classes

Name

Type

Comments

Win32_QuotaSetting

Dynamic

Contains setting information for disk quotas on a volume.

Win32_DiskQuota

Association

Tracks disk space usage for NTFS volumes.

Win32_VolumeQuotaSetting

Association

Relates disk quota settings with a specific disk volume.

These classes are available in the Root\CIMv2 namespace. The Win32_ DiskQuota association class associates the Win32_LogicalDisk class with the Win32_Account (see Figure 3.19).

click to expand
Figure 3.19: The Win32_DiskQuota association class.

With this association, it is possible to view and configure different quotas per user. We will exploit this capability in the next script sample. On the other hand, the Win32_QuotaSetting class is associated with the Win32_ LogicalDisk class via the Win32_VolumeQuotaSetting class (Figure 3.20).

click to expand
Figure 3.20: The Win32_QuotaSetting class associations.

With this association, it is possible to view and configure the default quota settings for each NTFS volume. In the previous chapter, when we examined the File System, we saw how to use the Win32_LogicalDisk class. To illustrate its use, we developed Samples 2.31 through 2.34 ("Gathering disk partition, disk drive, and logical disk information"). However, we skipped some lines (lines 245 through 267), because this piece of code was related to the disk quota information. These lines are presented in Sample 3.33.

Sample 3.33: Retrieving Disk quota information for each logical disk

start example

 ... ...: ...: 245: 246:              Set objWMIQuotaInstances = objWMIServices.ExecQuery _ 247:                             ("Associators of {Win32_LogicalDisk='" & _ 248:                              objWMILogicalDiskInstance.DeviceID & _ 249:                             "'} Where AssocClass=Win32_VolumeQuotaSetting"} 250: 251:              If objWMIQuotaInstances.Count Then 252:                 WScript.Echo 253:                 WScript.Echo " -- Quota information " & " " & String (63, "-") 254:                 For Each objWMIQuotaInstance In objWMIQuotaInstances 255:                     Set objWMIPropertySet = objWMIQuotaInstance.Properties_ 256:                     For Each objWMIProperty In objWMIPropertySet 257:                         DisplayFormattedProperty objWMIQuotaInstance, _ 258:                                                  "  "& objWMIProperty.Name, _ 259:                                                  objWMIProperty.Name, _ 260:                                                  Null 261:                     Next 262:                     Set objWMIPropertySet = Nothing 263:                 Next 264:              End If 265: 266:              Set objWMIQuotaInstances = Nothing 267: 

end example

In this sample, we use the association class Win32_VolumeQuotaSetting to retrieve the Win32_QuotaSetting instances associated with the Win32_ LogicalDisk (lines 246 through 249). Once the collection of instances is available, the script displays the disk quota information (lines 253 through 263). The quota information is available between lines 70 and 77 in the following output:

  1:   C:\>GetPartitionInformation.wsf  2:   Microsoft (R) Windows Script Host Version 5.6  3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.  4:  5:   - Disk #0, Partition #0 ------------------------------------------------------------  6:     BlockSize: ............................. 512  7:     Bootable: .............................. TRUE 15:     PrimaryPartition: ...................... TRUE 16:     Size: .................................. 843816960 17:     StartingOffset: ........................ 874782720 18:     Type: .................................. MS-DOS V4 Huge 19: 20:     -- Physical disk information ---------------------------------------------------- 21:     BytesPerSector: ........................ 512 22:     Capabilities: .......................... Random Access, Supports Writing 44:     TotalCylinders: ........................ 555 45:     TotalHeads: ............................ 240 46:     TotalSectors: .......................... 8391600 47:     TotalTracks: ........................... 133200 48:     TracksPerCylinder: ..................... 240 49: 50:     -- Logical disk information  ------------------------------------------------------- 51:     Compressed: ............................ FALSE 52:     Description: ........................... Local Fixed Disk 60:     QuotasDisabled: ........................ FALSE 61:     QuotasIncomplete: ...................... FALSE 62:     QuotasRebuilding: ...................... FALSE 63:     Size: .................................. 843816448 64:     SupportsDiskQuotas: .................... TRUE 65:     SupportsFileBasedCompression: .......... TRUE 66:     VolumeDirty: ........................... FALSE 67:     VolumeName: ............................ Whistler 68:     VolumeSerialNumber: .................... 988BD271 69: 70:     -- Quota information -------------------------------------------------------------- 71:     Caption: ............................... C: 72:     DefaultLimit: .......................... 1073741824 73:     DefaultWarningLimit: ................... 134217728 74:     ExceededNotification: .................. TRUE 75:     State: ................................. 1 76:     *VolumePath: ........................... C:\ 77:     WarningExceededNotification: ........... FALSE 

As mentioned previously, it is possible to configure a default quota per volume and a quota per user. To configure a default quota per volume, we must work with the Win32_QuotaSetting class. To configure a quota per user, we must work with the Win32_DiskQuota and exploit the associations in place (see Figure 3.19). Let's start with the default quota per volume first! The command-line parameters of the next script sample are as follows:

 C:\>WMIQuotaSetting.wsf Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. Usage: WMIQuotaSetting.wsf /Action:value /Volume:value [/DefaultLimit:value]                            [/DefaultWarningLimit[+|-]] [/ExceededNotification[+|-]]                            [/WarningExceededNotification[+|-]]                            [/Machine:value] [/User:value] [/Password:value] Options: Action                      : Specify the operation to perform: [List], [Disabled],                               [Tracked] and [Enforced]. Volume                      : Set the volume associated with the quota. DefaultLimit                : Set the default limit for the quota in MB. DefaultWarningLimit         : Set the default warning limit for the quota in MB. ExceededNotification        : Log event when a user exceeds quota limit. WarningExceededNotification : Log event when a user exceeds warning level. Machine                     : Determine the WMI system to connect to. (default=LocalHost) User                        : Determine the UserID to perform the remote connection. (default=none) Password                    : Determine the password to perform the remote                               Connection. (default=none) Examples:       WMIQuotaSetting.wsf /Action:List       WMIQuotaSetting.wsf /Volume:C: /Action:Disabled       WMIQuotaSetting.wsf /Volume:C: /Action:Tracked       WMIQuotaSetting.wsf /Volume:C: /Action:Enforced       WMIQuotaSetting.wsf /Volume:C: /Action:Enforced /DefaultWarningLimit:128 /DefaultLimit:256       WMIQuotaSetting.wsf /Volume:C: /Action:Enforced /DefaultWarningLimit:256 /DefaultLimit:NoLimit       WMIQuotaSetting.wsf /Volume:C: /Action:Enforced /DefaultWarningLimit:NoLimit /DefaultLimit:512       WMIQuotaSetting.wsf /Volume:C: /Action:Enforced /DefaultWarningLimit:128 /DefaultLimit:256                           /ExceededNotification+       WMIQuotaSetting.wsf /Volume:C  /Action:Enforced /DefaultWarningLimit:128 /DefaultLimit:256                           /WarningExceededNotification+ 

Each parameter exposed by the script corresponds exactly to the settings exposed by the Windows Explorer graphical interface to manage the default quota settings, as shown in Figure 3.21. By using the script, the configuration of Figure 3.21 can be obtained with the following command line:

 C:\>WMIQuotaSetting.wsf /Volume:C: /Action:Tracked 


Figure 3.21: The Windows Explorer quota management interface.

To configure all settings available, the following command line can be used:

 C:\>WMIQuotaSetting.wsf /Volume:C: /Action:Enforced /DefaultWarningLimit:128 /DefaultLimit:256                         /ExceededNotification+ /WarningExceededNotification+ 

This command line will enforce the quota settings to a maximum default limit of 256 MB with a default warning limit at 128 MB. Each time a user uses a quota higher than the warning limit or the maximum limit, an event log recod will be created in the system NT Event Log. Let's see how to script in Jscript the default quota configuration with Samples 3.34 and 3.35.

Sample 3.34: Viewing the default volume quotas (Part I)

start example

   1:<?xml version="1.0"?>   .:   8: <package>   9:  <job>  ..:  13:    <runtime>  ..:  36:    </runtime>  37:  38:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\DecodeVolumeQuotaStatusFunction.vbs" />  39:  40:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\DisplayFormattedPropertyFunction.vbs" />  41:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\TinyErrorHandler.vbs" />  42:  43:    <object progobjWMILocator'' reference="true"/>  44:  45:    <script language="Jscript">  46:    <![CDATA[  47:    var cComputerName = "LocalHost";  48:    var cWMINameSpace = "Root/cimv2";  49:    var cWMIQuotaSettingClass = "Win32_QuotaSetting";  50:  51:    var cQuotaNoLimit = "18446744073709551615";  ..:  77:    // --------------------------------------------------------------------------------  78:    // Parse the command line parameters  79:    if ((WScript.Arguments.Named.Count ==0) | | (WScript.Arguments.Named("Action") == null))  80:       {  81:       WScript.Arguments.ShowUsage();  82        WScript.Quit();  83:       } ...: 112:    varDefaultLimit = WScript.Arguments.Named("DefaultLimit"); 113:    if (varDefaultLimit != null) 114:       if (varDefaultLimit. toUpperCase() == "NOLIMIT") 115:          { 116:          varDefaultLimit = cQuotaNoLimit; 117:          } 118:       else 119:          { 120:          varDefaultLimit = varDefaultLimit.valueOf() * 1024 * 1024; 121:          ) 122: 123:    varDefaultWarningLimit = WScript.Arguments.Named("DefaultWarningLimit"); 124:    if (varDefaultWarningLimit != null) 125:       if (varDefaultWarningLimit.toUpperCase() == "NOLIMIT") 126:          { 127:          varDefaultWarningLimit = cQuotaNoLimit; 128:          } 129:       else 130:          { 131:          varDefaultWarningLimit = varDefaultWarningLimit.valueOf() * 1024 * 1024; 132:          } ...: 154: 155:    objWMILocator.Security_.AuthenticationLevel = wbemAuthenticationLevelDefault; 156:    objWMILocator.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate; 157: 158:    try 159:      { 160:      objWMIServices = objWMILocator.ConnectServer(strComputerName, cWMINameSpace, 161:                                                   strUserID, strPassword); 162:      } ...: 168:    // -- LIST -------------------------------------------------------------------------- 169:    if (boolList == true) 170:       { 171:       try 172:         { 173:         objWMIInstances = objWMIServices.InstancesOf (cWMIQuotaSettingClass) 174:         } ...: 180:       enumWMIInstances = new Enumerator (objWMIInstances); 181:       for (;! enumWMIInstances.atEnd(); enumWMIInstances.moveNext()) 182:           { 183:           objWMIInstance = enumWMIInstances.item(); 184: 185:           WScript.Echo ("- " + objWMIInstance.Caption + " " + 186:                         "------------------------------------------------------------------------------") ; 187: 188:           objWMIPropertySet = objWMIInstance.Properties_ 189:           enumWMIPropertySet = new Enumerator (objWMIPropertySet); 190:           for (;! enumWMIPropertySet.atEnd(); enumWMIPropertySet.moveNext()) 191:               { 192:               objWMIProperty = enumWMIPropertySet.item() 193: 194:               switch (objWMIProperty.Name) 195:                      { 196:                      case "State": 197:                          DisplayFormattedProperty (objWMIInstance, 198:                                                   "  " + objWMI Property. Name, 199:                                                   VolumeQuotaStatus (objWMIInstance.State), 200:                                                   null); 201:                          break; 202:                      case "DefaultLimit": 203:                          if (objWMIInstance.DefaultLimit == cQuotaNoLimit) 204:                             { 205:                             varDefaultLimit = "No Limit"; 206:                             } 207:                          else 208:                             { 209:                             varDefaultLimit = objWMIInstance.DefaultLimit; 210:                             } 211:                          DisplayFormattedProperty (objWMIInstance, 212:                                                   "  DefaultLimit (bytes)", 213:                                                   varDefaultLimit, 214:                                                   null); 215:                          break; 216:                     case 'DefaultWarningLimit'': 217:                          if (objWMIInstance.DefaultWarningLimit == cQuotaNoLimit) 218:                             { 219:                             varDefaultWarningLimit = "No Limit"; 220:                             } 221:                         else 222:                            { 223:                            varDefaultWarningLimit = objWMIInstance.DefaultWarningLimit; 224:                            } 225:                         DisplayFormattedProperty (objWMIInstance, 226:                                                  "  DefaultWarningLimit (bytes)'', 227:                                                  varDefaultWarningLimit, 228:                                                  null); 229:                         break; 230:                    default: 231:                         DisplayFormattedProperty (objWMIInstance, 232:                                                  "  " + objWMIProperty.Name, 233:                                                  objWMIProperty.Name, 234:                                                  null); 235:                         break; 236:                    } 237:                } 238:            WScript.Echo(); 239:            } 240:        ) 241: ...: ...: ...: 

end example

Sample 3.35: Configuring the default volume quotas (Part II)

start example

 ...: ...: ...: 241: 242:    // -- UPDATE ------------------------------------------------------------ 243:    if (intState > 0) 244:       { 245:       try 246:         { 247:         objWMIInstance = objWMIServices.Get ("Win32_QuotaSetting.VolumePath='" + 248:                                              strDeviceID + "\\'"); 249:         } ...: 255:       if (varDefaultLimit == null) 256:          { 257:          varDefaultLimit = objWMIInstance.DefaultLimit; 258:          } 259:       else 260:          { 261:          objWMIInstance.DefaultLimit = varDefaultLimit; 262:          } 263: 264:       if (varDefaultWarningLimit == null) 265:          { 266:          varDefaultWarningLimit = objWMIInstance.DefaultWarningLimit; 267:          } 268:       else 269:          { 270:          objWMIInstance.DefaultWarningLimit = varDefaultWarningLimit; 271:          } 272: 273:       if (boolExceededNotification == null) 274:          { 275:          boolExceededNotification = objWMIInstance.ExceededNotification; 276:          } 277:       else 278:          { 279:          objWMIInstance.ExceededNotification = boolExceededNotification; 280:          } 281: 282:       if (boolWarningExceededNotification == null) 283:          { 284:          boolWarningExceededNotification = objWMIInstance.WarningExceededNotification; 285:          } 286:       else 287:          { 288:          objWMIInstance.WarningExceededNotification = boolWarningExceededNotification; 289:          } 290: 291:       objWMIInstance.State = (intState - 1); 292: 293:       try 294:         { 295:         objWMIInstance.Put_ (wbemChangeFlagUpdateOnly | wbemFlagReturnWhenComplete); 296:         } ...: 302:       if (varDefaultLimit == cQuotaNoLimit) 303:          { 304:          varDefaultLimit = "No Limit"; 305:          } 306:       if (varDefaultWarningLimit == cQuotaNoLimit) 307:          { 308:          varDefaultWarningLimit = "No Limit"; 309:          } 310: 311:       WScript.Echo ("Default quota setting on '" + strDeviceID + "' updated."); 312:       WScript.Echo ("Quota is '" + VolumeQuotaStatus (objWMIInstance.State) + "' (" + 313:                     varDefaultWarningLimit + "' (bytes) / " + 314:                     varDefaultLimit + " (bytes))."); 315:       } 316: 317:    ]]> 318:    </script> 319:  </job> 320:</package> 

end example

Once the command-line parameter definition (lines 13 through 36) and parsing (lines 77 through 154) are completed, followed by the WMI connection (lines 155 through 162), the first portion of code allows the display of the current default quota settings (lines 169 through 240). Although the Jscript language is used in this example, you will easily recognize the traditional structure to display all available instances (lines 180 through 239) with their properties (lines 188 through 237). Every volume able to support disk quotas will be displayed. We will obtain the same information as obtained from Samples 2.31 through 2.34 but without any related disk, partition, or volume information, since we are not working with the associations in this example. The most interesting part of this sample concerns the scripting logic used to enable the disk quotas and to set the miscellaneous settings. This portion of the code is shown in Sample 3.35.

Because NTFS volumes are the only ones supporting quotas, a Win32_QuotaSetting instance is always available when the selected volume is an NTFS volume. Therefore, there is no need to create a Win32_QuotaSetting instance for a volume. However, the script must be able to update that Win32_QuotaSetting instance accordingly with the parameters given on the command line. This means that if only some parameters are given, other values must not be destroyed. For example, if the following command line is given:

 1:   C:\>WMIQuotaSetting.wsf /Volume:C: /Action:Enforced /DefaultWarningLimit:256                              /WarningExceededNotification+ 2:   Microsoft (R) Windows Script Host Version 5.6 3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. 4: 5:   Default quota setting on 'C:' updated. 6:   Quota is 'Enforced' (268435456 (bytes) / No Limit (bytes)). 

The warning limit will be fixed to 256 MB, and an NT Event Log trace will be created once this warning limit is reached. However, the hard limit is not specified on the command line and, as Figure 3.21 shows, there is no hard limit configured. The script takes care of this missing parameter and does not change its existing value. This logic is implemented by testing the miscellaneous variables assigned by the command-line parameters. If the command-line parameter was given, the variable contains a value; otherwise, the variable is equal to Null (see lines 255, 264, 273, and 282). If the variable is Null, the current property instance value is assigned to the variable (lines 257, 266, 275, and 284). If the variable has a value, the new value is assigned to the corresponding property instance (lines 261, 270, 279, and 288).

It is important to note that when no quota limit is set the assigned value is equal to 18446744073709551615 (2^64 - 1). This value is defined in the script header at line 51. If the keyword "NoLimit" is assigned, the command-line parsing code assigns the correct value to reflect the "No Limit" configuration setting (lines 112 through 132). The WMI state property (line 291) determines if the quota management must be disabled, tracked, or enforced. Each of these states corresponds to a value of the state property: 0=Disabled, 1 =Tracked, and 2=Enforced.

Once the examined instance is modified, the changes must be committed back to the system. This update is executed at lines 293 through 296. Once completed, the script displays a message showing the current configuration.

To configure a quota per user, as mentioned previously, the Win32_DiskQuota with its associations must be used. This is the purpose of the next sample, also written in Jscript. Its command-line parameters are as follows:

 C:\>WMIQuota.wsf Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. Usage: WMIQuota.wsf /Action:value /Account:value /Volume:value [/Limit:value]                     [/WarningLimit:value] [/Machine:value] [/User:value] [/Password:value Options: Action       : Specify the operation to perform: [List], [Create], [Update] and [Delete]. Account      : Set the account associated with the quota. Volume       : Set the volume associated with the quota. Limit        : Set the limit for the quota in MB. WarningLimit : Set the warning limit for the quota in MB. Machine      : Determine the WMI system to connect to. (default=LocalHost) User         : Determine the UserID to perform the remote connection. (default=none) Password     : Determine the password to perform the remote connection. (default=none) Examples:       WMIQuota.wsf /Action:List       WMIQuota.wsf /Account:LISSWARENET\Alain.Lissoir /Volume:C: /Limit:512 /WarningLimit:256                    /Action:Create       WMIQuota.wsf /Account:LISSWARENET\Alain.Lissoir /Volume:C: /Limit:NoLimit /WarningLimit:256                    /Action:Create       WMIQuota.wsf /Account:LISSWARENET\Alain.Lissoir /Volume:C: /Limit:512 /WarningLimit:NoLimit                    /Action:Create       WMIQuota.wsf /Account:LISSWARENET\Alain.Lissoir /Volume:C: /Limit:1024 /Action:Update       WMIQuota.wsf /Account:LISSWARENET\Alain.Lissoir /Volume:C: /Limit:NoLimit /Action:Update       WMIQuota.wsf /Account:LISSWARENET\Alain.Lissoir /Volume:C: /WarningLimit:512 /Action:Update       WMIQuota.wsf /Account:LISSWARENET\Alain.Lissoir /Volume:C: /WarningLimit:NoLimit                    /Action:Update       WMIQuota.wsf /Account:LISSWARENET\Alain.Lissoir /Volume:C: /Action:Delete 

Because the command-line parameters and parsing always use the same structure, Sample 3.36 does not show this portion of the code. We also skipped the portion of the code showing all available instances with their properties, since it also uses a script logic used many times now (lines 203 through 316). The first interesting piece of code in Sample 3.36 concerns the user quota creation (lines 319 through 389).

Sample 3.36: Viewing, creating, updating, and deleting volume quota per user (Part I)

start example

   1:<?xml version="1.0"?>   .:   8:<package>   9:  <job>  ..:  13:    <runtime>  ..:  35:    </runtime>  36:  37:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\DecodeQuotaStatusInfoFunction.vbs" />  38:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\ExtractUserIDFunction.vbs" />  39:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\ExtractUserDomainFunction.vbs" />  40:  41:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\DisplayFormattedPropertyFunction.vbs'' />  42:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\TinyErrorHandler.vbs" />  43:  44:    <object prog  reference="true''/>  45:    <object progobjWMIDateTime" />  46:  47:    <script language="Jscript">  48:    <![CDATA[  49:  50:    var cComputerName = "LocalHost";  51:    var cWMINameSpace = "Root/cimv2";  52:    var cWMIDiskQuotaClass = "Win32_DiskQuota";  53:    var cWMIAccountClass = "Win32_Account";  54:    var cWMILogicalDiskClass = "Win32_LogicalDisk" ;  55:  56:    var cQuotaNoLimit = "18446744073709551615"; ...: 189:    objWMILocator.Security_.AuthenticationLevel = wbemAuthenticationLevelDefault; 190:    objWMILocator.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate; 191: 192:    try 193:      { 194:      objWMIServices = objWMILocator.ConnectServer(strComputerName, cWMINameSpace, 195:                                                   strUserID, strPassword); 196:      } ...: 201: 202:    // -- LIST -------------------------------------------------------------------------- 203:    if (boolList == true) 204:       { ...: 316:       } 317: 318:    // -- CREATE ------------------------------------------------------------------------ 319:    if (boolCreate == true) 320:       { 321:       try 322:         { 323:         objWMIClass = objWMIServices.Get (cWMIDiskQuotaClass); 324:         } ...: 329: 330:       objWMIInstance = objWMIClass.SpawnInstance_(); 331: 332:       try 333:         { 334:         objWMIUserInstance = objWMIServices.Get (cWMIAccountClass + ".Domain='" + 335:                                                  strDomain + "',Name='" + strName + "'"); 336:         } ...: 342:       try 343:         { 344:         objWMIDiskInstance = objWMIServices.Get (cWMILogicalDiskClass + "='" + 345:                                                  strDeviceID + "'"); 346:         } ...: 352:       objWMIInstance.User = objWMIUserInstance.Path_.RelPath; 353:       objWMIInstance.QuotaVolume = objWMIDiskInstance.Path_.RelPath; 354: 355:       if (varLimit == null) 356:          { 357:          varLimit = cQuotaNoLimit; 358:          } 359: 360:       if (varWarningLimit == null) 361:          { 362:          varWarningLimit = cQuotaNoLimit; 363:          } 364: 365:       objWMIInstance.Limit = varLimit; 366:       objWMIInstance.WarningLimit = varWarningLimit; 367: 368:       try 369:         { 370:          objWMIInstance.Put_ (wbemChangeFlagCreateOrUpdate | wbemFlagReturnWhenComplete); 371:         } ...: 377:       if (objWMIInstance.Limit == cQuotaNoLimit) 378:         { 379:         varLimit = "No Limit"; 380:         } 381:       if (objWMIInstance.WarningLimit == cQuotaNoLimit) 382:         { 383:         varWarningLimit = "No Limit"; 384:         } 385: 386:       WScript.Echo ("Quota on '" + strDeviceID + "' for '" + 387:                    strDomain + "\\" + strName + "' created (" + 388:                    varWarningLimit + " (bytes) / " + varLimit + " (bytes))."); 389:       } ...: ...: ...: 

end example

Because the Win32_DiskQuota class is an association class, its creation is a bit unusual, because it is made up of references. First, a new instance of the Win32_DiskQuota is created (lines 321 through 330) and because the class is an association class that associates a Win32_UserAccount and a Win32_LogicalDisk, the code must retrieve these associated instances by using the information given on the command-line parameters (/Account and /Volume switches). This operation is executed from line 332 through 336 for the Win32_Account instance and from line 342 through 346 for the Win32_LogicalDisk instance. Once these two instances are available, their WMI paths are assigned to the Win32_DiskQuota references (lines 352 and 353). If there is no quota limit specified for the user quota creation, by default the script does not define a limit (lines 355 through 363). Next, the script commits the changes to the system (lines 368 through 371).

Besides the user quota creation, the script is also able to handle existing user quota modifications. This portion of the code is shown in Sample 3.37.

Sample 3.37: Updating volume quota per user (Part II)

start example

 ...: ...: ...: 390: 391:    // -- UPDATE -------------------------------------------------------------------------- 392:    if (boolUpdate == true) 393:       ( 394:       try 395:         ( 396:         objWMIInstance = objWMIServices.Get ("Win32_DiskQuota.QuotaVolume=\"" + 397:                                             "Win32_LogicalDisk.DeviceID='" + 398:                                             strDeviceID + "'\'"' + 399:                                             ",User=\"" + "Win32_Account.Domain='" + 400:                                             strDomain + "',Name='" + strName + "'\""); 401:         } ...: 407:       if (varLimit == null) 408:          ( 409:          varLimit = objWMIInstance.Limit; 410:          } 411:       else 412:          { 413:          objWMIInstance.Limit = varLimit; 414:          } 415: 416:       if (varWarningLimit == null) 417:          { 418:          varWarnintjLimit = objWMIInstance.WarnintjLimit; 419:          } 420:       else 421:          ( 422:          objWMIInstance.WarnintjLimit = varWarnintjLimit; 423:          ) 424: 425:       try 426:         { 427:         objWMIInstance.Put_ (wbemChangeFlagUpdateOnly | wbemFlagReturnWhenComplete) 428:         } ...: 434:       if (objWMIInstance.Limit == cQuotaNoLimit) 435:          { 436:          varLimit = "No Limit"; 437:          } 438:       if (objWMIInstance.WarningLimit == cQuotaNoLimit) 439:          { 440:          varWarningLimit = "No Limit"; 441:          } 442: 443:       WScript.Echo ("Quota on '" + strDeviceID + "' for '" + 444:                    strDomain + "\\" + strName + "' updated (" + 445:                    varWarningLimit + " (bytes) / " + varLimit + " (bytes))."); 446:       } 447: ...: ...: ...: 

end example

To update a user quota, we must first retrieve the user quota instance. This is done from line 396 through 400. The WMI path of a Win32_DiskQuota instance is made up of the Key properties. This is why it is a bit more complex to code. For example, a Win32_DiskQuota path will be coded as follows:

 Win32_DiskQuota.QuotaVolume="Win32_LogicalDisk.DeviceID=\"C:\"",                 User="Win32_Account.Domain=\"NET-DPEN6400A\",                 Name=\"Administrators\"" 

Once the Win32_DiskQuota instance is retrieved, the miscellaneous settings will be configured based on the command-line parameters given (lines 407 through 423) and committed back to the system (lines 425 through 428). The logic used here is exactly the same as in Sample 3.35—it takes care of the parameters not specified on the command line.

The last supported operation is the deletion of a user quota (see Sample 3.38). This operation has nothing unusual about it. It retrieves the user quota instance to delete (lines 453 through 457), and then deletes that instance with the Delete_ method of the SWBemObject (lines 464 through 467).

Sample 3.38: Deleting volume quota per user (Part III)

start example

 ...: ...: ...: 447: 448:    // -- DELETE --------------------------------------------------------------------------- 449:    if (boolDelete == true) 450:       { 451:       try 452:         { 453:         objWMIInstance = objWMIServices.Get ("Win32_DiskQuota.QuotaVolume=\"" + 454:                                              "Win32_LogicalDisk.DeviceID='" + 455:                                              strDeviceID + "'\"" + 456:                                              ",User=\"" + "Win32_Account.Domain='" + 457:                                              strDomain + "',Name=' " + strName + "'\"" ); 458:         } ...: 464:       try 465:         { 466:         objWMIInstance.Delete_(); 467:         } ...: 473:       WScript.Echo ("Quota on '" + strDeviceID + "' for '" + 474:                    strDomain + "\\" + strName + "' deleted."); 475:       } 476: 477:    ]]> 478:    </script> 479:  </job> 480:</package> 

end example

3.5.2 DFS provider

Distributed File System (DFS) is the ability to logically group shares from multiple servers and to link these shares transparently. All the linked shares appear in a treelike structure within a single Root. The DFS provider supports the configuration and the management of DFS in Windows Server 2003. Table 3.44 shows the DFS provider capabilities.

Table 3.44: The DFS Providers Capabilities

Provider Name

Provider Namespace

Class Provider

Instance Provider

Method Provider

Property Provider

Event Provider

Event Consumer Provider

Support Get

Support Put

Support Enumeration

Support Delete

Windows Server 2003

Windows XP

Windows 2000 Server

Windows 2000 Professional

Windows NT 4.0

DFS Provider

DFSProvider

Root/CIMV2

X

X

X

X

X

X

X

Table 3.45 summarizes the classes supported by the DFS provider. All classes are available in the Root\CIMv2 namespace.

Table 3.45: The DFS Provider Classes

Name

Type

Comments

Win32_DfsTarget

Dynamic

The DfsTarget class represents a target of a DFS link.

Win32_DfsNode

Dynamic

The Win32_DfsNode class represents a root or a link of a domain based or a standalone distributed file system (DFS).

Win32_DfsNodeTarget

Association

The Win32_DfsNodeTarget class associates a DFS node to one of its targets.

With this provider it is possible to create DFS nodes and use associations to represent the connections between nodes, shares, and servers linked to the nodes. Figure 3.22 represents this association.

click to expand
Figure 3.22: The Win32_ DFSNodeTarget association class.

A DFS Root can be defined at the domain level for domain-based operation or at the server level for standalone operation. Domain-based DFS can have multiple Roots in the domain but only one Root on each server. The Create method of the Win32_DfsNode can be used to create new nodes.

Sample 3.39 and 3.40 show how to retrieve, create, update, and delete DFS nodes. The script exposes the following command-line parameters:

 C:\>WMIDFS.Wsf Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. Usage: WMIDfs.wsf /Action:value /Share:value /Server:value /RootDFS:value                   [/LinkState:value] [/TimeOut:value] [/Description:value]                   [/Machine:value] [/User:value] [/Password:value] Options: Action      : Specify the operation to perform: [ViewRootNodes], [ViewNodes], [Create],               [Update] and [Delete]. Share       : The ShareName indicates the name of the share that the link references. Server      : The ServerName indicates the name of the server that the link references. RootDFS     : The Root DFS Node that represents a link of a domain based or a standalone DFS. LinkState   : Indicates the state of the DFS link. Only [Offline], [Online] or               [Active] are accepted. TimeOut     : Indicates the time in seconds for which the client caches the referral of a node. Description : Textual description of a Node. Machine     : Determine the WMI system to connect to. (default=LocalHost) User        : Determine the UserID to perform the remote connection. (default=none) Password    : Determine the password to perform the remote connection. (default=none) Examples:       WMIDFS.Wsf /Action:ViewRootNodes       WMIDFS.Wsf /Action:ViewNodes       WMIDFS.Wsf /Action:Create /Share:SubDirectory_9 /Server:NET-DPEN6400A.LissWare.Net                  /RootDFS:\\LISSWARENET\MyDFSRoot /Description:"DFS Node to SubDirectory_1"       WMIDFS.Wsf /Action:Update /Share:SubDirectory_9 /Server:NET-DPEN6400A.LissWare.Net                  /RootDFS:\\LISSWARENET\MyDFSRoot /Timeout:10       WMIDFS.Wsf /Action:Update /Share:SubDirectory_9 /Server:NET-DPEN6400A.LissWare.Net                  /RootDFS:\\LISSWARENET\MyDFSRoot /LinkState:OffLine       WMIDFS.Wsf /Action:Update /Share:SubDirectory_9 /Server:NET-DPEN6400A.LissWare.Net                  /RootDFS:\\LISSWARENET\MyDFSRoot /LinkState:OnLine       WMIDFS.Wsf /Action:Update /Share:SubDirectory_9 /Server:NET-DPEN6400A.LissWare.Net                  /RootDFS:\\LISSWARENET\MyDFSRoot /LinkState:Active       WMIDFS.Wsf /Action:Delete /Share:SubDirectory_9 /Server:NET-DPEN6400A.LissWare.Net                  /RootDFS:\\LISSWARENET\MyDFSRoot 

Sample 3.39: Viewing, creating, modifying, and deleting DFS nodes (Part I)

start example

   1:<?xml version="1.0"?>   .:   8:<package>   9:  <job>  ..:  13:    <runtime>  ..:  36:    </runtime>  37:  38:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\DecodeDFSStateFunction.vbs" />  39:  40:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\DisplayFormattedPropertyFunction.vbs" />  41:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\TinyErrorHandler.vbs" />  42:  43:    <object progobjWMILocator'' reference= "true"/>  44:    <object progobjWMIDateTime" />  45:  46:    <script language="VBscript">  47:    <![CDATA[  ..:  51:    Const cComputerName = "LocalHost"  52:    Const cWMINameSpace = "Root/cimv2''  53:    Const cWMIDfsNodeClass = "Win32_DfsNode"  54:    Const cWMIDfsTargetClass = "Win32_DfsTarget"  ..:  84:    ' -------------------------------------------------------------------------------------  85:    ' Parse the command line parameters  86:    If WScript.Arguments.Named.Count = 0 Then  87:       WScript.Arguments.ShowUsage()  88:       WScript.Quit  89:    End If  90:  91:    Select Case Ucase(WScript.Arguments.Named("Action"))  92:           Case "VIEWROOTNODES"  93:                boolList = True  94:                boolDFSRootNodes = True  95:           Case "VIEWNODES"  96:                boolList = True  97:                boolDFSRootNodes = False  98:           Case "CREATE"  99:                boolCreate = True 100:           Case "UPDATE" 101:                boolUpdate = True 102:           Case "DELETE" 103:                boolDelete = True 104:           Case Else 105:                WScript.Echo "Invalid action type. Only [List], [Create], [Update] ... 106:                WScript.Arguments.ShowUsage() 107:                WScript.Quit 108:    End Select ...: 159:    strComputerName = WScript.Arguments.Named("Machine") 160:    If Len(strComputerName) = 0 Then StrComputerName = cComputerName 161: 162:    objWMILocator.Security_.AuthenticationLevel = wbemAuthenticationLevelDefault 163:    objWMILocator.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate 164: 165:    Set objWMIServices = objWMILocator.ConnectServer(strComputerName, cWMINameSpace, _ 166:                                                     strUserID, strPassword) ...: 169:    ' -- LIST -------------------------------------------------------------------------------------- 170:    If boolList = True Then 171: 172:    Set objWMIInstances = objWMIServices.InstancesOf (cWMIDfsNodeClass) ...: 175:    If objWMIInstances.Count Then 176:       For Each objWMIInstance in objWMIInstances 177:           If boolDFSRootNodes = objWMIInstance.Root Then 178:              WScript.Echo "- Node: " & objWMIInstance.Name & String (60, "-") 179: 180:              Set objWMIPropertySet = objWMIInstance.Properties_ 181:              For Each objWMIProperty In objWMIPropertySet 182:                  Select Case objWMIProperty.Name 183:                         Case "Caption" 184: 185:                         Case "State" 186:                              DisplayFormattedProperty objWMIInstance, _ 187:                                     "  " & objWMIProperty.Name, _ 188:                                     DecodeDFSNodeState (objWMIProperty.Value), _ 189:                                     Null 190:                         Case Else 191:                              DisplayFormattedProperty objWMIInstance, _ 192:                                     "  " & objWMIProperty.Name, _ 193:                                     objWMIProperty.Value, _ 194:                                     Null 195:                  End Select 196:              Next ...: 199:              Set objWMIAssocInstances = objWMIServices.ExecQuery _ 200:                                                        ("Associators of {" & _ 201:                                                        objWMIInstance.Path_.RelPath & "}") 202: 203:              For Each objWMIAssocInstance In objWMIAssocInstances 204:                  WScript.Echo vbCRLF & " - Target Link: \\" & _ 205:                               objWMIAssocInstance.ServerName & _ 206:                               "\" & objWMIAssocInstance.ShareName & _ 207:                               " " & String (60, "-") 208:                  Set objWMIPropertySet = objWMIAssocInstance.Properties_ 209:                  For Each objWMIProperty In objWMIPropertySet 210:                      Select Case objWMIProperty.Name 211:                             Case "Caption" 212: 213:                             Case "State" 214:                                  DisplayFormattedProperty objWMIInstance, _ 215:                                         "  " & objWMIProperty.Name, _ 216:                                         DecodeDFSTargetState (objWMIProperty.Value), _ 217:                                         Null 218:                             Case Else 219:                                  DisplayFormattedProperty objWMIInstance, _ 220:                                         "  " & objWMIProperty.Name, _ 221:                                         objWMIProperty.Value, _ 222:                                         Null 223:                      End Select 224:                  Next ...: 226:              Next ...: 230:                 WScript.Echo 231:              End If 232:          Next 233:       Else 234:          WScript.Echo "No DFS nodes available." 235:       End If ...: 239:    End If 240: ...: ...: ...: 

end example

Sample 3.40: Viewing, creating, modifying, and deleting DFS nodes (Part II)

start example

 ...: ...: ...: 240: 241:    ' -- CREATE ------------------------------------------------------------------------- 242:    If boolCreate = True Then 243:       Set objWMIClass = objWMIServices.Get (cWMIDfsNodeClass) ...: 246:       intRC = objWMIClass.Create (strRootDFS & "\" & strShare, _ 247:                                   strServer, _ 248:                                   strShare, _ 249:                                   strDescription) 250: 251:       If intRC = 0 Then 252:          WScript.Echo "DFS node '" & strRootDFS & "\" & strShare & "' successfully created." 253:       Else 254:          WScript.Echo "Failed to create DFS node '" & strRootDFS & "\" & _ 255:                        strShare & "' (0x" & Hex (IntRC) & ")." 256:       End If ...: 259:    End If 260: 261:    ' -- UPDATE ------------------------------------------------------------------------- 262:    If boolUpdate = True Then 263:       if intTimeout Then 264:          Set objWMIInstance = objWMIServices.Get (cWMIDfsNodeClass & "='" & _ 265:                                                   strRootDFS & "\" & strShare & "'") ...: 268:          objWMIInstance.Timeout = intTimeout 269: 270:          objWMIInstance.Put_ (wbemChangeFlagUpdateOnly Or wbemFlagReturnWhenComplete) ...: 272:       End If 273: 274:       If intLinkState Then 275:          Set objWMIInstance = objWMIServices.Get (cWMIDfsTargetClass & ".LinkName='" & _ 276:                                                   strRootDFS & "\" & strShare & _ 277:                                                   "',ServerName='" & strServer & _ 278:                                                   "',ShareName='" & strShare & "'") ...: 281:          objWMIInstance.State = intLinkState - 1 282: 283:          objWMIInstance.Put_ (wbemChangeFlagUpdateOnly Or wbemFlagReturnWhenComplete) ...: 285:       End If 286: 287:       WScript.Echo "DFS Node '" & strRootDFS & "\" & strShare & "' successfully updated." ...: 290:    End If 291: 292:    ' -- DELETE ------------------------------------------------------------------------- 293:    If boolDelete = True Then 294:       Set objWMIInstance = objWMIServices.Get (cWMIDfsNodeClass & "='" & _ 295:                                                strRootDFS & "\" & strShare & "'") ...: 298:       objWMIInstance.Delete_ ...: 301:       WScript.Echo "DFS Node '" & strRootDFS & "\" & strShare & "' successfully deleted." ...: 304:    End If ...: 308:    ]]> 309:    </script> 310:  </job> 311:</package> 

end example

The first part of the script (Sample 3.39) defines and parses the command-line parameters (skipped lines 13 through 36 and lines 86 through 160). Next, after the WMI connection (lines 162 through 165), based on the value of the /Action switch, the script retrieves the Win32_DFSNode instances (lines 169 through 239).

At line 172, the script retrieves all instances from the Win32_DFSNode class. Next, it uses the usual scripting technique to display the Win32_DFSNode instance properties (lines 176 through 232). The /Action:ViewRootNodes or /Action:ViewNodes switches determine if the DFS node Root instances must be displayed by performing a comparison of the switch value with the Root property of the Win32_DFSNode instance (line 177). Next, it displays the properties of the instance accordingly (lines 180 through 196).

As shown in Figure 3.22, the Win32_DFSNode class is associated with the Win32_DFSTarget by the Win32_DfsNodeTarget association class. The script takes advantage of this association (lines 199 through 201) to display information about the Win32_DFSTarget instances (lines 203 through 224).

For a configuration similar to the one shown in Figure 3.23, the script execution with the /Action:ViewRootNodes switch will produce an output similar to the following one:

  1:   C:\>WMIDFS.Wsf /Action:ViewRootNodes  2:   Microsoft (R) Windows Script Host Version 5.6  3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.  4:  5:   - Node: \\LISSWARENET\MyDFSRoot-------------------------------------------------------------  6:     Description: ........................... My Domain DFS Root  7:     Name: .................................. \\LISSWARENET\MyDFSRoot  8:     Root: .................................. True  9:     State: ................................. Ok 10:     Timeout: ............................... 30 11: 12:     - Target Link: \\NET-DPEN6400A\MyDFSRoot ------------------------------------------------- 13:     LinkName: .............................. \\LISSWARENET\MyDFSRoot 14:     ServerName: ............................ NET-DPEN6400A 15:     ShareName: ............................. MyDFSRoot 16:     State: ................................. OnLine. 

click to expand
Figure 3.23: A DFS configuration example.

From line 5 through 10, we see the Win32_DFSNode instance properties and from line 12 through 16, we see the Win32_DFSTarget instance properties associated with it.

The script execution with the /Action:ViewNodes switch will produce an output similar to the following one:

  1:   C:\>WMIDFS.Wsf /Action:ViewNodes  2:   Microsoft (R) Windows Script Host Version 5.6  3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.  4:  5:   - Node: \\LISSWARENET\MyDFSRoot\SubDirectory_3----------------------------------------------  6:     Description: ........................... SubDirectory_3  7:     Name: .................................. \\LISSWARENET\MyDFSRoot\SubDirectory_3  8:     Root: .................................. False  9:     State: ................................. OnLine 10:     Timeout: ............................... 10 11: 12:     - Target Link: \\NET-DPEN6400A.LissWare.Net\SubDirectory_3 ----------------------------- 13:     LinkName: .............................. \\LISSWARENET\MyDFSRoot\SubDirectory_3 14:     ServerName: ............................ NET-DPEN6400A.LissWare.Net 15:     ShareName: ............................. SubDirectory_3 16:     State: ................................. OnLine. 17: 18:     - Node: \\LISSWARENET\MyDFSRoot\SubDirectory_8-------------------------------------------- 19:       Description: ........................... SubDirectory_8 20:       Name: .................................. \\LISSWARENET\MyDFSRoot\SubDirectory_8 21:       Root: .................................. False 22:       State: ................................. OnLine 23:       Timeout: ............................... 10 24: 25:       - Target Link: \\NET-DPEN6400A.LissWare.Net\SubDirectory_8 --------------------------- 26:       LinkName: .............................. \\LISSWARENET\MyDFSRoot\SubDirectory_8 27:       ServerName: ............................ NET-DPEN6400A.LissWare.Net 28:       ShareName: ............................. SubDirectory_8 29:       State: ................................. OffLine. ..: ..: ..: 

The output is similar to the previous one. However, only Win32_DFSNode non-Root instances are displayed. You will notice that the state of the "SubDirectory_8" is offline (line 29), as shown in Figure 3.23.

Sample 3.40, which is the second part of the script, creates (lines 242 through 259), modifies (lines 262 through 290), and deletes (lines 293 through 304) existing Win32_DFSNode instances.

The creation of a Win32_DFSNode instance is performed with the Create static method exposed by the Win32_DFSNode class. This method requires four parameters, as follows:

  • The DFS path parameter, which specifies the path of the DFS Root (which comes from the command line with the /RootDFS switch).

  • The Server name parameter, which specifies the name of the server that hosts the share to which the DFS link is associated (which comes from the command line with the /Server switch).

  • The ShareName parameter, which specifies the name of the share to which the DFS link is associated (which comes from the command line with the /Share switch).

  • The Description parameter, which specifies a comment describing the DFS node (which comes from the command line with the /Description switch).

The Win32_DFSNode instance creation is executed at line 246. Next, the script tests if the Create method returned a value different from zero. Any value returned from the execution of this method states that an error occurred. These values correspond to the Win32 errors (where corresponding messages are available with a "Net HelpMsg <value>" command).

The Win32_DFSNode class and the Win32_DFSTarget class allow the modification of some properties of the instances they represent. The Win32_DFSNode exposes a Timeout property to indicate the time in seconds for which the client caches the referral of this node. The script can modify this property (lines 264 through 270) by retrieving the corresponding Win32_DFSNode instance in an SWBemObject object (lines 264 and 265) and invoking the Put_ method (line 270).

In the same way, it is possible to modify the state of a Win32_DFSTarget instance by changing the value of the State property (lines 274 through 285). The State property indicates the state of the DFS target. Note that both Win32_DFSNode and Win32_DFSTarget classes expose a State property. Table 3.46 shows the meaning of the different values for each class.

Table 3.46: The State Property Meaning of the Win32_DFSNode and Win32_Target Classes

Win32_DFSNode State property values

Meaning

Values

Ok

0

Inconsistent

1

OnLine

2

OffLine

3

Win32_DFSTarget State property values

Meaning

Values

OffLine

0

OnLine

1

Active

4

To delete a Win32_DFSNode instance, the script retrieves an instance of a DFS node (lines 294 and 295) and invokes the Delete_ method of the SWBemObject representing the Win32_DFSNode instance (line 298).

3.5.3 Shadow Copy providers

The Shadow Copy providers provide management capabilities to the Windows Server 2003 shadow copy services. The user interface exposing information related to this new feature is available by right-clicking on a volume, selecting properties, and clicking again on the Shadow Copies pane (see Figure 3.24). Bear in mind that this feature is only available under Windows Server 2003.

click to expand
Figure 3.24: Managing the Shadow Copies of a volume from the user interface.

The set of properties and actions available from the user interface is also accessible from WMI. The Shadow Copy providers supporting these features are registered in the Root\CIMv2 namespace of the CIM repository (see Table 3.47).

Table 3.47: The Shadow Copy Providers Capabilities

Provider Name

Provider Namespace

Class Provider

Instance Provider

Method Provider

Property Provider

Event Provider

Event Consumer Provider

Support Get

Support Put

Support Enumeration

Support Delete

Windows Server 2003

Windows XP

Windows 2000 Server

Windows 2000 Professional

Windows NT 4.0

Shadow Copy Providers

MSVSS__PROVIDER

Root/CIMV2

X

X

X

X

X

X

X

MSVDS__PROVIDER

Root/CIMV2

X

X

X

X

X

X

X

These providers support a set of classes exposing properties and methods to perform most of the Shadow Copy tasks (see Table 3.48). The most relevant classes to use from a scripting point of view are the Win32_Volume, Win32_ShadowCopy, and Win32_ShadowStorage classes.

Table 3.48: The Shadow Copy Providers Classes

Name

Type

Comments

Win32_ShadowCopy

Dynamic

The Win32_ShadowCopy class is a storage extent that represents a duplicate copy of the original volume at some previous time.

Win32_ShadowProvider

Dynamic

The Win32_ShadowProvider class represents a component, typically a combination of user-mode and kernel/firmware implementation, that will perform the work involved in creating and representing volume shadow copies.

Win32_Volume

Dynamic

The Win32_Volume class represents an area of storage on a hard disk. The class returns local volumes that are formatted, unformatted, mounted, or offline. A volume is formatted by using a file system, such as FAT or NTFS, and may have a drive letter assigned to it. A single hard disk can have multiple volumes, and volumes can also span multiple disks.

Win32_MountPoint

Association

The mount point associates a volume to the directory at which it is mounted.

Win32_ShadowBy

Association

The association between a shadow copy and the provider that created the shadow copy.

Win32_ShadowDiffVolumeSupport

Association

The association between a shadow copy provider and a volume supported for differential storage area.

Win32_ShadowFor

Association

The association between a shadow copy and the volume for which the shadow was created.

Win32_ShadowOn

Association

The association between a shadow copy and the volume on which differential data is written.

Win32_ShadowStorage

Association

The association between the volume for which a shadow copy is made and the volume to which the differential data is written.

Win32_ShadowVolumeSupport

Association

The association between a shadow copy provider and a supported volume.

Win32_VolumeQuota

Association

The Win32_VolumeQuota association relates per volume quota settings.

Win32_VolumeUserQuota

Association

The Win32_VolumeUserQuota association relates per user quotas to quota-enabled volumes. System administrators can configure Windows to prevent further disk space use and log an event when a user exceeds a specified disk space limit. They can also log an event when a user exceeds a specified disk space warning level. Note that disk quotas cannot be set for the Administrator accounts themselves.

It is interesting to note that the Win32_Volume class is quite similar to the Win32_LogicalDisk class. For instance, it is possible to invoke the Chkdsk method from the Win32_Volume class, as we did in Sample 2.3 with the Win32_LogicalDisk class. Both Chkdsk method implementations expose the exact same input parameters. However, the Win32_Volume class exposes some extra properties and methods especially related to the Shadow Copy features. Actually, during the design phase of the Shadow Copy object model, it had been noted that the current Win32_LogicalDisk class was not providing enough information to suit the requirements. Therefore, Microsoft decided to create the Win32_Volume class to suit its needs. That's why this class implements some methods of the Win32_LogicalDisk class (i.e., Chkdsk, ExcludeFromAutoChk, ScheduleAutoChk) with some new methods and functionalities to request information about the defragmentation analysis, perform a defragmentation, format a volume (i.e., Defrag, DefragAnalysis, Format), mount or dismount a volume, and manage shadow copies. However, there are sseveral noteworthy differences between Win32_LogicalDisk and Win32_Volume classes. These are as follows:

  • The Win32_Volume class does not manage floppy disk drives.

  • The Win32_Volume class can be used to change the volume drive letter, while the Win32_LogicalDisk does not support this.

  • Win32_Volume class enumerates all volumes, not just those with drive letters similar to the Win32_LogicalDisk class.

  • The Win32_Volume class does not enumerate network shares that are mapped to drive letters similar to the Win32_LogicalDisk class.

Besides the Win32_Volume class, another very interesting class is the Win32_ShadowCopy class. Instances of this class represent the shadow copies of the original volume at some previous time. The Win32_Volume and Win32_ShadowCopy classes are associated with the Win32_ShadowFor and Win32_ShadowOn association classes (see Figure 3.25). The Win32_ShadowCopy class exposes the Create method to create shadow copies, which corresponds to the "Create Now" button shown in Figure 3.24.

click to expand
Figure 3.25: The Win32_Volume class and its associations.

The final, most relevant class is the Win32_ShadowStorage class. This class is an association class linking the Win32_Volume class with the Win32_Volume class itself. The purpose of this association class is to expose some properties visible in the user interface (see Figure 3.24—i.e., used space, allocated space, and the maximum space) and create an association between a volume that contains information to be shadowed and a volume containing the shadows. Some interesting properties of the Win32_ShadowStorage class are, for example, AllocatedSpace, MaxSpace, and UsedSpace, where MaxSpace can be updated.

A very interesting aspect of the Shadow Copy object model is the existence of associations between the Win32_Volume class and the Win32_QuotaSetting class (see Figure 3.25). Similar to the Win32_LogicalDisk class, by managing the volumes with the Win32_Volume class, it is possible to retrieve and manage disk quota information. However, we will not cover the disk quota management in the next script sample, since the logic and coding technique are exactly the same as samples working with the Win32_LogicalDisk and Win32_QuotaSettings classes (see Samples 3.33 through 3.38).

Samples 3.41 through 3.52 illustrate how to work with these three Shadow Copy classes. The command-line parameters supported by the script expose most methods and manageable properties of the classes.

 C:\>WMIDiskSvc.wsf /? Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. Usage: WMIDiskSvc.wsf Volume [/Action:value] [/ShadowCopy[+|-]] [/Force[+|-]] [/FileSystem:value]                              [/ClusterSize:value] [/Label:value] [/Compression[+|-]]                              [/FixErrors[+|-]] [/VigorousIndexCheck[+|-]] [/SkipFolderCycle[+|-]]                              [/ForceDismount[+|-]] [/RecoverBadSectors[+|-]] [/OKToRunAtBootUp[+|-]]                              [/MaxSpace:value] [/ShadowStorage:value] [/ShadowCopyID:value]                              [/Machine:value] [/User:value] [/Password:value] Options: Volume             : The logical disk letter (i.e., C: or D:). Action             : Determines the action to perform. Only [List], [Format], [DefragAnalysis],                      [Defrag], [Dismount], [Chkdsk], [CreateShadowCopy], [DeleteShadowCopy],                      [CreateShadowStorage], [UpdateShadowStorage] or [DeleteShadowStorage] is                      accepted. ShadowCopy         : Only list the shadow copies available on the system. Force              : Forces the defrag even if free space on the disk is low. FileSystem         : Determines the filesystem to use for the formatted volume.                      Only [NTFS], [FAT] or [FAT32]. ClusterSize        : Determines the volume cluster size to use. Label              : Determines the volume label. Compression        : Enables the compression on the formatted volume. FixErrors          : Indicates what should be done to errors found on the disk. If true, then errors                      are fixed. The default is FALSE. VigorousIndexCheck : If TRUE, a vigorous check of index entries should be performed.                      The default is TRUE. SkipFolderCycle    : If TRUE, the folder cycle checking should be skipped or not.                      The default is TRUE. ForceDismount      : If TRUE, the drive should be forced to dismount before checking.                      The default is FALSE. RecoverBadSectors  : If TRUE, the bad sectors should be located and the readable information should                      be recovered from these sectors. The default is FALSE. OKToRunAtBootUp    : If TRUE, the chkdsk operation should be performed at next boot up time,                      in case the operation could not be performed because the disk was locked at                      time the method was called. The default is FALSE. MaxSpace           : Determines the maximum space to be used on the Shadow Storage. ShadowStorage      : Determines the volume to use to store the Shadows. ShadowCopyID       : Specifies the shadow copy ID to delete. Machine            : Determines the WMI system to connect to. (default=LocalHost) User               : Determines the UserID to perform the remote connection. (default=none) Password           : Determines the password to perform the remote connection. (default=none) Example:       WMIDiskSvc.wsf /Action:List       WMIDiskSvc.wsf /Action:List /ShadowCopy+       WMIDiskSvc.wsf C: /Action:DefragAnalysis       WMIDiskSvc.wsf C: /Action:Defrag /Force+       WMIDiskSvc.wsf C: /Action:Format /FileSystem:NTFS                         /QuickFormat+ /ClusterSize:4096 /Label:"MyDisk" /Compression+       WMIDiskSvc.wsf C: /Action:Chkdsk /FixErrors+ /VigorousIndexCheck+ /SkipFolderCycle+       WMIDiskSvc.wsf C: /Action:Chkdsk /ForceDismount+ /RecoverBadSectors+ /OKToRunAtBootUp+       WMIDiskSvc.wsf C: /Action:CreateShadowStorage /MaxSpace:850 /ShadowStorage:Z:       WMIDiskSvc.wsf C: /Action:UpdateShadowStorage /MaxSpace:Unlimited       WMIDiskSvc.wsf C: /Action:DeleteShadowStorage       WMIDiskSvc.wsf C: /Action:CreateShadowCopy       WMIDiskSvc.wsf /Action:DeleteShadowCopy /ShadowCopyID:{a2e1d5d6-4bab-4bd8-b133-dad5798ec9ff} 

As usual, the first part of the script defines (skipped lines 13 through 59) and parses (skipped lines 130 through 274) the command-line parameters. Next, it executes the WMI connection (lines 276 through 280).

Sample 3.41: Managing disk services and shadow copies (Part I)

start example

   1:<?xml version="1.0"?>   .:   8:<package>   9:  <job>  ..:  13:    <runtime>  ..:  59:    </runtime>  60:  61:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\DisplayFormattedPropertiesFunction.vbs" />  62:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\DisplayFormattedPropertyFunction.vbs" />  63:    <script language="VBScript" src="/books/2/679/1/html/2/..\Functions\TinyErrorHandler.vbs" />  64:  65:    <object prog  reference="true"/>  66:    <object prog  />  67:  68:    <script language="VBscript">  69:    <![CDATA[  ..:  73:    Const cComputerName = "LocalHost"  74:    Const cWMINameSpace = "root/cimv2"  75:  76:    Const cUnlimitedMaxSpace = "18446744073709551615" ...: 130:    ' -------------------------------------------------------------------------------- 131:    ' Parse the command line parameters 132:    strAction = WScript.Arguments.Named("Action") 133:    Select Case UCase (strAction) 134:           Case "LIST" 135:                boolShadowCopy = WScript.Arguments.Named("ShadowCopy") 136:                If Len(boolShadowCopy) = 0 Then boolShadowCopy = False 137: 138:                boolList = True 139: 140:           Case "CHKDSK" ...: 267:    strUserID = WScript.Arguments.Named("User") 268:    If Len(strUserID) = 0 Then strUserID = "" 269: 270:    strPassword = WScript.Arguments.Named("Password") 271:    If Len(strPassword) = 0 Then strPassword = "" 272: 273:    strComputerName = WScript.Arguments.Named("Machine") 274:    If Len(strComputerName) = 0 Then strComputerName = cComputerName 275: 276:    objWMILocator.Security_.AuthenticationLevel = wbemAuthenticationLevelDefault 277:    objWMILocator.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate 278: 279:    Set objWMIServices = objWMILocator.ConnectServer(strComputerName, cWMINameSpace, _ 280:                                                     strUserID, strPassword) ...: 282: ...: ...: ...: 

end example

The first feature supported by the script is the ability to list all shadow copies available on a system. This feature requires a very basic scripting technique, since it simply requests all instances of the Win32_ShadowCopy class and displays all properties of each instance. This capability will be useful when we will need to delete a shadow copy with WMI. Actually, the key property to retrieve a Win32_ShadowCopy instance is a GUID number exposed by the ID property. This is why it is interesting to implement a function listing all Win32_ShadowCopy instances with their properties (see Sample 3.42).

Sample 3.42: Viewing all Win32_ShadowCopy instances (Part II)

start example

 ...: ...: ...: 282: 283:    ' -- List Shadow Copy --------------------------------------------------------------------- 284:    If boolList = True And boolShadowCopy = True Then 285:       Set objWMIInstances = objWMIServices.InstancesOf ("Win32_ShadowCopy") ...: 288:       If objWMIInstances.Count Then 289:          For Each objWMIInstance In objWMIInstances 290:              objWMIDateTime.Value = objWMIInstance.InstallDate 291: 292:              WScript.Echo "- Shadow Copy: (" & objWMIDateTime.GetVarDate (False) & _ 293:                           ") " & String (60, "-") 294: 295:              Set objWMIPropertySet = objWMIInstance.Properties_ 296:              For Each objWMIProperty In objWMIPropertySet 297:                  DisplayFormattedProperty objWMIInstance, _ 298:                         objWMIProperty.Name, _ 299:                         objWMIProperty.Name, _ 300:                         Null 301:              Next ...: 304:       Next 305:    Else 306:       WScript.Echo "No shadow copy available." 307:    End If 308:    End If 309: ...: ...: ...: 

end example

As an example, the script will display the following information:

  1:   C:\>WMIDiskSvc.wsf /Action:List /ShadowCopy+  2:   Microsoft (R) Windows Script Host Version 5.6  3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.  4:  5:   - Shadow Copy: (28-10-2002 22:37:09) -------------------------------------------------------  6:   ClientAccessible: ........................ TRUE  7:   Count: ................................... 1  8:   DeviceObject: ............................ \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy13  9:   Differential: ............................ FALSE 10:   ExposedLocally: .......................... FALSE 11:   ExposedRemotely: ......................... FALSE 12:   HardwareAssisted: ........................ FALSE 13:   *ID: ..................................... {2f26b83b-d583-461d-b773-e6cd024f9710} 14:   Imported: ................................ FALSE 15:   InstallDate: ............................. 28-10-2002 22:37:09 16:   NoAutoRelease: ........................... TRUE 17:   NotSurfaced: ............................. FALSE 18:   NoWriters: ............................... TRUE 19:   OriginatingMachine: ...................... net-dpep6400a.Emea.LissWare.NET 20:   Persistent: .............................. TRUE 21:   Plex: .................................... FALSE 22:   ProviderID: .............................. {b5946137-7b9f-4925-af80-51abd60b20d5} 23:   ReadWrite: ............................... FALSE 24:   ServiceMachine: .......................... net-dpep6400a.Emea.LissWare.NET 25:   SetID: ................................... {238304a1-3df0-4d0e-9f16-d143abe87a29} 26:   State: ................................... 12 27:   Transportable: ........................... FALSE 28:   VolumeName: .............................. \\?\Volume{3eed7424-a3b2-11d6-a5f4-806e6f6e6963}\ 

Of course, if we are able to list the shadow copies available in a system, it is possible to create new shadow copies by using the Win32_ShadowCopy class and its Create method, as shown in Sample 3.43. It is interesting to note that the Create method is a static method. Therefore, the method does not relate to a particular Win32_ShadowCopy dynamic instance. Instead, an instance of the class must be created to invoke the method (line 314). From line 316 through 318, the method requests two input parameters (the drive letter and the context used by the WMI provider to create the shadow, which is always "Client Accessible") and returns one output parameter (which is the ID of the created shadow) displayed at line 324.

Sample 3.43: Creating new shadow copies (Part III)

start example

 ...: ...: ...: 309: 310:    ' -- CreateShadowCopy --------------------------------------------------------------------- 311:    If boolCreateShadowCopy = True Then 312:       WScript.Echo "Creating shadow copy ..." 313: 314:       Set objWMIClass = objWMIServices.Get ("Win32_ShadowCopy") 315: 316:       intRC = objWMIClass.Create (strWMIDriverLetter & "\", _ 317:                                   "ClientAccessible", _ 318:                                   strShadowCopyID) ...: 321:       If intRC Then 322:          WScript.Echo "Shadow copy creation error (" & intRC & ")." 323:       Else 324:          WScript.Echo "Shadow copy '" & strShadowCopyID & "' successfully created." 325:       End If 326:    End If 327: ...: ...: ...: 

end example

To create a shadow copy, the following command line must be used:

 1:   C:\>WMIDiskSvc.wsf D: /Action:CreateShadowCopy 2:   Microsoft (R) Windows Script Host Version 5.6 3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. 4 5:   Creating shadow copy ... 6:   Shadow copy  {2f26b83b-d583-461d-b773-e6cd024f9710}'  successfully created. 

To delete shadow copies, the scripting technique is a little bit different from the creation technique. Instead of using a method exposed by the Win32_ShadowCopy class, the script (see Sample 3.44) retrieves the Win32_ShadowCopy instance to be deleted by referring the ID passed on the command-line parameters with the /ShadowCopylD switch (lines 332 and 333). Once the instance is retrieved, the script invokes the Delete_ method exposed by the SWBemObject object (line 336) representing the Win32_ShadowCopy instance. The following command line will execute the routine shown in Sample 3.44:

 1:   C:\>WMIDiskSvc.wsf /Action:DeleteShadowCopy /ShadowCopyID:{2f26b83b-d583-461d-b773-e6cd024f9710) 2:    Microsoft (R) Windows Script Host Version 5.6 3:    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. 4: 5:    Deleting shadow copy ... 6:    Shadow Copy '(2f26b83b-d583-461d-b773-e6cd024f9710)' successfully deleted. 

Sample 3.44: Deleting shadow copies (Part IV)

start example

 ...: ...: ...: 327: 328:    ' --DeleteShadowCopy -------------------------------------------------------------------------------------— 329:    If boolDeleteShadowCopy = True Then 330:       WScript.Echo "Deleting shadow copy ..." 331: 332:       Set objWMIInstance = objWMIServices.Get ("Win32_ShadowCopy='" & _ 333:                                                strShadowCopyID & "'") ...: 336:       objWMIInstance.Delete_ 339:       WScript.Echo "Shadow Copy '" & StrShadowCopyID & "' successfully deleted." ...: 342:    End If 343: ...: ...: ...: 

end example

A shadow storage is an association between two volumes (which is simply an association between two Win32_Volume instances). To create a shadow storage, the script uses the Create static method exposed by the Win32_ShadowStorage association class (see Sample 3.45, lines 352 through 354).

Sample 3.45: Associating a shadow storage with a Win32_Volume instance (Part V)

start example

 ...: ...: ...: 343: 344:    ' -- Create Shadow Storage ---------------------------------------------------------------- 345:    If boolCreateShadowStorage = True Then 346:       If Len (strShadowStorage) Then 347:          WScript.Echo "Defining Shadow Storage area for volume  " & _ 348:                       strWMIDriverLetter & "' on volume '" & _ 349:                       strShadowStorage & "'..." 350: 351:          Set objWMIClass = objWMIServices.Get ("Win32_ShadowStorage") 352:          intRC = objWMIClass.Create (strWMIDriverLetter & "\", _ 353:                                      strShadowStorage & "\", _ 354:                                      varMaxSpace) 355:          If intRC Then 356:             WScript.Echo "Shadow Storage creation error (" & intRC & ").' 357:          Else 358:             WScript.Echo "Shadow Storage '" & StrWMIDriverLetter & _ 359:                          "' successfully defined for volume '" & _ 360:                          strShadowStorage & "'.' 361:          End If ...: 363:       End If 364:    Else ...: ...: ...: 

end example

The Create method exposes three parameters: the drive letter of the volume containing the data to shadow, the driver letter of the volume used to store the shadows, and the maximum disk space to allocate on that volume. Once the method execution successfully completes, the Win32_ShadowStorage association instance is created. The command line to use for this operation is:

 1:   C:\>WMIDiskSvc.wsf D: /Action:CreateShadowStorage /MaxSpace:850 /ShadowStorage:Z: 2:   Microsoft (R) Windows Script Host Version 5.6 3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. 4: 5:   Defining Shadow Storage area for volume 'D:' on volume 'Z:'... 6:   Shadow Storage 'D:' successfully defined for volume 'Z:'. 

Samples 3.46 through 3.52 relate to different operations regarding the Win32_Volume instances. Sample 3.46 shows how to list all Win32_Volume instances with their associated Win32_ShadowStorage and Win32_ShadowCopy instances. Actually, the script exploits the associations illustrated in Figure 3.25.

Sample 3.46: Viewing the volumes with their related shadow storage and shadow copies (Part VI)

start example

 ...: ...: ...: 364:    Else 365:       Set objWMIInstances = objWMIServices.InstancesOf ("Win32_Volume") ...: 368:       For Each objWMIInstance In objWMIInstances 369: 370:           ' -- List -------------------------------------------------------------------------- 371:           If boolList = True And boolShadowCopy = False Then 372:              WScript.Echo "- " & objWMIInstance.DriveLetter & " " & _ 373:                           String (60, "-") 374: 375:              Set objWMIPropertySet = objWMIInstance.Properties_ 376:              For Each objWMIProperty In objWMIPropertySet 377:                  DisplayFormattedProperty objWMIInstance, _ 378:                         objWMIProperty.Name, _ 379:                         objWMIProperty.Name, _ 380:                         Null 381:              Next ...: 384:              Set objWMIAssociatedInstances = objWMIServices.ExecQuery _ 385:                        ("References of {" & _ 386:                        objWMIInstance.Path_.RelPath & _ 387:                        "} Where Role=Volume " & _ 388:                        "ResultClass=Win32_ShadowStorage") ...: 391:              For Each objWMIAssociatedInstance In objWMIAssociatedInstances 392: 393:                  WScript.Echo vbCRLF & " - Shadow Storage: " & String (60, "-") 394: 395:                  Set objWMIPropertySet = objWMIAssociatedInstance.Properties_ 396:                  For Each objWMIProperty In objWMIPropertySet 397:                      DisplayFormattedProperty objWMIAssociatedInstance, _ 398:                             "   " & objWMIProperty.Name, _ 399:                             objWMIProperty.Name, _ 400:                             Null 401:                  Next ...: 403:              Next 404: 405:              Set objWMIAssociatedInstances = objWMIServices.ExecQuery _ 406:                        ("Associators of {" & _ 407:                        objWMIInstance.Path_.RelPath & _ 408:                        "} Where AssocClass=Win32_ShadowFor") ...: 411:              For Each objWMIAssociatedInstance In objWMIAssociatedInstances 412: 413:                  WScript.Echo vbCRLF & " - Shadow Copy: " & _ 414:                               objWMIAssociatedInstance.ID & _ 415:                               " " & String (20, "-") 416: 417:                  Set objWMIPropertySet = objWMIAssociatedInstance.Properties_ 418:                  For Each objWMIProperty In objWMIPropertySet 419:                      DisplayFormattedProperty objWMIAssociatedInstance, _ 420:                             "   " & objWMIProperty.Name, _ 421:                             objWMIProperty.Name, _ 422:                             Null 423:                  Next ...: 425:              Next 426: 427:              WScript.Echo 428:           Else ...: ...: ...: 

end example

First, Sample 3.46 requests all instances of the Win32_Volume class (line 365) and performs a loop (Sample 3.46, line 368, through Sample 3.52, line 596) to show the properties of each instance found in the collection (lines 372 through 382). Actually, this loop embraces many more operations than simply showing all instances of the Win32_Volume class. It is also used to find a specific instance of the Win32_Volume class when one Win32_Volume instance must be retrieved to perform a specific operation, such as a check disk or a defragmentation (Sample 3.47, line 429).

Sample 3.47: Executing the Chkdsk Win32_Volume method (Part VII)

start example

 ...: ...: ...: 428:            Else 429:               If Ucase (objWMIInstance.DriveLetter) = Ucase (strWMIDriverLetter) Then 430: 431:                  ' -- Chkdsk ------------------------------------------------------------------ 432:                  If boolChkdsk Then 433:                     If boolFixErrors Then 434:                        WScript.Echo "Errors will be fixed." 435:                     End If 436: 437:                     If boolVigorousIndexCheck Then 438:                        WScript.Echo "Vigorous check of index entries will be performed." 439:                     End If 440: 441:                     If boolSkipFolderCycle Then 442:                        WScript.Echo "The folder cycle checking will be skipped." 443:                     End If 444: 445:                     If boolForceDismount Then 446:                        WScript.Echo "The drive will be forced to dismount before checking." 447:                     End If 448: 449:                     If boolRecoverBadSectors Then 450:                        WScript.Echo "The bad sectors will be ... recovered from these sectors." 451:                     End If 452: 453:                     If boolOKToRunAtBootUp Then 454:                        WScript.Echo "The chkdsk ... performed at next boot up time." 455:                     End If 456: 457:                     WScript.Echo 458:                     WScript.Echo "Volume " & Ucase (objWMIInstance.DriveLetter) & _ 459:                                  " has " & objWMIInstance.FreeSpace & _ 460:                                  " bytes free on a total of " & _ 461:                                  objWMIInstance.Capacity & " bytes." 462:                     WScript.Echo "The type of the file system is " & _ 463:                                  objWMIInstance.FileSystem & "." 464:                     WScript.Echo "Volume is " & objWMIInstance.Label & "." 465:                     WScript.Echo "Volume Serial Number is " & _ 466:                       Right ("0000" & Hex(int (objWMIinstance.SerialNumber / 65536)), 4) & _ 467:                       "-" & _ 468:                       Right ("0000" & Hex(objWMIinstance.SerialNumber And 65535), 4) & _ 469:                       "." 470: 471:                     WScript.Echo "WMI chkdsk started ..." 472:                     intRC = objWMIInstance.Chkdsk (boolFixErrors, _ 473: boolVigorousIndexCheck, _ 474:                                                    boolSkipFolderCycle, _ 475:                                                    boolForceDismount, _ 476:                                                    boolRecoverBadSectors, _ 477:                                                    boolOKToRunAtBootUp) ...: 480:                     Select Case intRC 481:                            Case 0 482:                                 WScript.Echo "WMI chkdsk completed successfully." 483:                            Case 1 484:                                 WScript.Echo "Locked and chkdsk scheduled on reboot." 485:                            Case 2 486:                                 WScript.Echo "WMI chkdsk failure - Unknown file system." 487:                            Case 3 488:                                 WScript.Echo "WMI chkdsk failure - Unknown error." 489:                     End Select 490:                  End If 491: ...: ...: ...: 

end example

But let's come back to Sample 3.46 and how the associated classes are retrieved (lines 384 through 388 and lines 405 through 408). During the loop listing all Win32_Volume instances, Sample 3.46 retrieves the associated shadow storage instance (lines 384 through 388). The shadow storage is materialized in the CIM repository by an instance of the Win32_ShadowStorage association class. Usually, there is always one Win32_ShadowStorage association instance per Win32_Volume instance. Therefore, the script uses the following WQL data query to retrieve the Win32_ShadowStorage instance (lines 384 through 388):

 References of {Win32_Volume.Device}                Where Role=Volume ResultClass=Win32_ShadowStorage 

This query is directly inspired by the relationship that exists between the Win32_Volume class and the Win32_ShadowStorage association class (see Figure 3.25).

In the same way, to retrieve the Win32_ShadowCopy instances associated with the Win32_Volume instance, the script uses another WQL data query (lines 405 through 408):

 Associators of {Win32_Volume.Device}                 Where AssocClass=Win32_ShadowFor 

Another interesting question, but not implemented in the current script, concerns the volumes using a specific volume for shadow storage. This question can be answered by using the following query:

 Associators of {Win32_Volume.Device)                 Where AssocClass=Win32_ShadowStorage ResultRole=Volume" 

For each instance retrieved by the WQL data queries, the script displays all properties. A sample output would be as follows:

  1:   C:\>WMIDiskSvc.wsf /Action:List  2:   Microsoft (R) Windows Script Host Version 5.6  3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.  4:  5:   - C: ------------------------------------------------------------  6:   Automount: ............................... TRUE  7:   BlockSize: ............................... 2048  8:   Capacity: ................................ 2144376832  9:   Caption: ................................. C:\ 10:   Compressed: .............................. FALSE 11:   *DeviceID: ............................... \\?\Volume{3eed7422-a3b2-11d6-a5f4-806e6f6e6963}\ 12:   DirtyBitSet: ............................. FALSE 13:   DriveLetter: ............................. C: 14:   DriveType: ............................... 3 15:   FileSystem: .............................. NTFS 16:   FreeSpace: ............................... 782168064 17:   IndexingEnabled: ......................... TRUE 18:   InstallDate: ............................. 01-01-2000 19:   Label: ................................... Windows Server 2003 20:   MaximumFileNameLength: ................... 255 21:   Name: .................................... C:\ 22:   QuotasEnabled: ........................... FALSE 23:   QuotasIncomplete: ........................ FALSE 24:   QuotasRebuilding: ........................ FALSE 25:   SerialNumber: ............................ 615808770 26:   SupportsDiskQuotas: ...................... TRUE 27:   SupportsFileBasedCompression: ............ TRUE 28:   SystemName: .............................. NET-DPEP6400A 29: 30:   - D: ------------------------------------------------------------ 31:   Automount: ............................... TRUE 32:   BlockSize: ............................... 4096 33:   Capacity: ................................ 7222730752 ..: 50:   SerialNumber: ............................ 821048372 51:   SupportsDiskQuotas: ...................... TRUE 52:   SupportsFileBasedCompression: ............ TRUE 53:   SystemName: .............................. NET-DPEP6400A 54: 55:      - Shadow Storage: ------------------------------------------------------------ 56:      AllocatedSpace: ....................... 104857600 57:      *DiffVolume: .......................... Win32_Volume.DeviceID=                                          "\\\\?\\Volume{3eed7423-a3b2-11d6-a5f4-806e6f6e6963}\\" 58:      MaxSpace: ............................. 891289600 59:      UsedSpace: ............................ 1064960 60:      *Volume: .............................. Win32_Volume.DeviceID=                                          "\\\\?\\Volume{3eed7424-a3b2-11d6-a5f4-806e6f6e6963}\\" 61: 62:      - Shadow Copy: {2f26b83b-d583-461d-b773-e6cd024f9710} -------------------- 63:      ClientAccessible: ..................... TRUE 64:      Count: ................................ 1 65:      DeviceObject: ......................... \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy13 66:      Differential: ......................... FALSE 67:      ExposedLocally: ....................... FALSE 68:      ExposedRemotely: ...................... FALSE 69:      HardwareAssisted: ..................... FALSE 70:      *ID: .................................. {2f26b83b-d583-461d-b773-e6cd024f9710} 71:      Imported: ............................. FALSE 72:      InstallDate: .......................... 28-10-2002 22:37:09 73:      NoAutoRelease: ........................ TRUE 74:      NotSurfaced: .......................... FALSE 75:      NoWriters: ............................ TRUE 76:      OriginatingMachine: ................... net-dpep6400a.Emea.LissWare.NET 77:      Persistent: ........................... TRUE 78:      Plex: ................................. FALSE 79:      ProviderID: ........................... {b5946137-7b9f-4925-af80-51abd60b20d5} 80:      ReadWrite: ............................ FALSE 81:      ServiceMachine: ....................... net-dpep6400a.Emea.LissWare.NET 82:      SetID: ................................ {238304a1-3df0-4d0e-9f16-d143abe87a29} 83:      State: ................................ 12 84:      Transportable: ........................ FALSE 85:      VolumeName: ........................... \\?\Volume{3eed7424-a3b2-11d6-a5f4-806e6f6e6963}\ 86: 87:   - E: ------------------------------------------------------------ 88:   Automount: ............................... TRUE 89:   BlockSize: ............................... 4096 90:   Capacity: ................................ 7222759424 91:   Caption: ................................. E:\ 92:   Compressed: .............................. FALSE 93:   *DeviceID: ............................... \\?\Volume{3eed7425-a3b2-11d6-a5f4-806e6f6e6963}\ ..: ..: ..: 

Sample 3.47 shows how to use the Chkdsk method exposed by the Win32_Volume class. This method is not a static method and therefore relates to a specific Win32_Volume instance. This is the reason why the method invocation is executed inside the loop (Sample 3.46, line 368, and Sample 3.52, line 596) and for a specific Win32_Volume instance (Sample 3.47, line 429). The method parameters and usage are exactly the same as the Win32_LogicalDisk method (see Sample 2.3).

A small difference to note is the data type of the volume serial number. The Win32_LogicalDisk class exposes the volume serial number in the VolumeSerialNumber property in a hexadecimal string, while the Win32_Volume class exposes the serial number in the SerialNumber property as a 32-bit integer. This is why Sample 3.47 includes some extra logic to display the volume serial number in a hexadecimal format (lines 466 through 469).

The ability to request the defragmentation statistics and perform a defragmentation is a very interesting feature of the Win32_Volume class (see Sample 3.48 and 3.49). Both methods are very easy to use. Each of them relates to a specific instance of the Win32_Volume class. The DefragAnalysis method exposes two output parameters (lines 496 and 497): a Boolean variable informing if the defragmentation is recommended and an SWbemObject made from the Win32_DefragAnalysis class to return defragmentation statistics. The command line to use and the output obtained are as follows:

 C:\>WMIDiskSvc.wsf D: /Action:DefragAnalysis Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. Defragmentation analysis started ... Defragmentation is NOT recommended. - Win32_DefragAnalysis ------------------------------------------------------------ AverageFileSize: ......................... 141980 AverageFragmentsPerFile: ................. 1 ClusterSize: ............................. 4096 ExcessFolderFragments: ................... 0 FilePercentFragmentation: ................ 0 FragmentedFolders: ....................... 1 FreeSpace: ............................... 1724788736 FreeSpacePercent: ........................ 23 FreeSpacePercentFragmentation: ........... 2 MFTPercentInUse: ......................... 84 MFTRecordCount: .......................... 55029 PageFileSize: ............................ 0 TotalExcessFragments: .................... 360 TotalFiles: .............................. 52188 TotalFolders: ............................ 2790 TotalFragmentedFiles: .................... 12 TotalMFTFragments: ....................... 2 TotalMFTSize: ............................ 66368512 TotalPageFileFragments: .................. 0 TotalPercentFragmentation: ............... 1 UsedSpace: ............................... 5497942016 VolumeSize: .............................. 7222730752 

Sample 3.48: Executing the DefragAnalysis Win32_Volume method (Part VIII)

start example

 ...: ...: ...: 491: 492:               ' -- Defragmentation Analysis ------------------------------------------------ 493:               If boolDefragAnalysis = True Then 494:                  WScript.Echo "Defragmentation analysis started ..." 495: 496:                  intRC = objWMIInstance.DefragAnalysis (boolDefragRecommended, _ 497:                                                         objDefragAnalysis) ...: 500:                  If intRC Then 501:                     WScript.Echo "Defragmentation analysis error (" & inRC & ").' 502:                  Else 503:                     If boolDefragRecommended Then 504:                        WScript.Echo vbCRLF & "Defragmentation is recommended." 505:                     Else 506:                        WScript.Echo vbCRLF & "Defragmentation is NOT recommended." 507:                     End If 508:                     DisplayFormattedProperties objDefragAnalysis, 0 509:                  End If 510:               End If 511: ...: ...: ...: 

end example

Sample 3.49: Executing the Defrag Win32_Volume method (Part IX)

start example

 ...: ...: ...: 511: 512:                 ' -- Defragmentation --------------------------------------------------------- 513:                 If boolDefrag = True Then 514:                    WScript.Echo "Defragmentation started ..." 515: 516:                    intRC = objWMIInstance.Defrag (boolForce, objDefragAnalysis) ...: 519:                    If intRC Then 520:                       WScript.Echo "Defragmentation error (" & inRC & ")." 521:                    Else 522:                       DisplayFormattedProperties objDefragAnalysis, 0 523:                    End If 524:                 End If 525: ...: ...: ...: 

end example

The invocation of the Win32_Volume Defrag method follows the same coding technique as the DefragAnalysis method (see Sample 3.49). The only difference resides in the method parameters, where one input parameter is required to eventually force the volume defragmentation and one output parameter is available to return the defragmentation analysis information (line 516). The execution of this code portion of the script is made with the following command line:

 C:\>WMIDiskSvc.wsf D: /Action:Defrag Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. Defragmentation started ... - Win32_DefragAnalysis ------------------------------------------------------------ AverageFileSize: ......................... 141980 AverageFragmentsPerFile: ................. 1 ClusterSize: ............................. 4096 ExcessFolderFragments: ................... 0 FilePercentFragmentation: ................ 0 FragmentedFolders: ....................... 1 FreeSpace: ............................... 1724788736 FreeSpacePercent: ........................ 23 FreeSpacePercentFragmentation: ........... 2 MFTPercentInUse: ......................... 84 MFTRecordCount: .......................... 55029 PageFileSize: ............................ 0 TotalExcessFragments: .................... 16 TotalFiles: .............................. 52188 TotalFolders: ............................ 2790 TotalFragmentedFiles: .................... 1 TotalMFTFragments: ....................... 2 TotalMFTSize: ............................ 66368512 TotalPageFileFragments: .................. 0 TotalPercentFragmentation: ............... 1 UsedSpace: ............................... 5497942016 VolumeSize: .............................. 7222730752 

With the Format method of the Win32_Volume class, it is possible to format a volume (see Sample 3.50). Basically, this method implements the functionality of the FORMAT.COM command. The Format method accepts five input parameters: the file system type (NTFS, FAT, or FAT32), a Boolean variable defining the formatting mode (true=quick or false=normal), the cluster size (by default 4,096), the volume label, and a Boolean variable to enable the compression (lines 530 through 534). The latter is actually not implemented, even if it is required to invoke the method.

Sample 3.50: Executing the Format Win32_Volume method (Part X)

start example

 ...: ...: ...: 525: 526:               '-- Format ------------------------------------------------------------------ 527:               If boolFormat = True Then 528:                  WScript.Echo ''Format started ..." 529: 530:                  intRC = objWMIInstance.Format (strFileSystem, _ 531:                                                 boolQuickFormat, _ 532:                                                 intClusterSize, _ 533:                                                 strLabel, _ 534:                                                 boolCompression) ...: 537:                  If intRC Then 538:                     WScript.Echo ''Format error (" & intRC & ")." 539:                  Else 540:                     WScript.Echo "Format completed successfully." 541:                  End If 542:               End If 543: ...: ...: ...: 

end example

If a shadow storage volume is associated with a Win32_Volume instance, it is possible to update the maximum disk space that can be allocated to the shadow copies. To do so, it is necessary to retrieve the association instance made from the Win32_ShadowStorage class (see Sample 3.51). The execution of a WQL data query from the Win32_Volume instance representing the disk containing the information to shadow will retrieve the association Win32_ShadowStorage instance (lines 549 through 552). The WQL data query will be as follows for a given Win32_Volume instance:

 References of {Win32_Volume.Device} Where ResultClass=Win32_ShadowStorage 

Sample 3.51: Updating a Win32_ShadowStorage instance (Part XI)

start example

 ...: ...: ...: 543: 544:              ' -- Update Shadow Storage --------------------------------------------------- 545:              If boolUpdateShadowStorage = True Then 546:                 If varMaxSpace <> -1 Then 547:                    WScript.Echo "Updating maximum space for the shadow volume ..." 548: 549:                    Set objWMIAssociatedInstances = objWMIServices.ExecQuery _ 550:                              ("References of {" & _ 551:                              objWMIInstance.Path_.RelPath & _ 552:                              "} Where ResultClass=Win32_ShadowStorage") ...: 555:                    If objWMIAssociatedInstances.Count = 1 Then 556:                       For Each objWMIAssociatedlnstance In objWMIAssociatedInstances 557:                           objWMIAssociatedInstance.MaxSpace = varMaxSpace 558: 559:                           objWMIAssociatedInstance.Put_ (wbemChangeFlagCreateOrUpdate Or _ 560:                                                           wbemFlagReturnWhenComplete) ...: 562:                       Next 563: 564:                       WScript.Echo "Maximum space for Shadow Storage successfully updated." 565:                    Else 566:                       WScript.Echo ''No Shadow Storage for volume '" & strWMIDriverLetter 567:                    End If 568:                 End If 569:              End If 570: ...: ...: ...: 

end example

To create a Win32_ShadowStorage instance, Sample 3.45 ("Associating a shadow storage with a Win32_Volume instance [Part V]") requests a drive letter and a disk space allocated to the shadows. Actually, the disk space value can be updated after the Win32_ShadowStorage instance creation by examining the MaxSpace property of the corresponding Win32_ShadowStorage instance (see Sample 3.51). This Win32_ShadowStorage instance can be retrieved with a WQL data query similar to the previous one (lines 549 through 552). As mentioned previously, there is only one instance of the Win32_ShadowStorage class per Win32_Volume instance. This is the reason why the script tests the number of results at line 555. Because a WQL data query returns the result in a collection, by enumerating the collection (lines 556 through 562), it is possible to update the MaxSpace property of the Win32_ShadowStorage instances (line 557). From the user interface (see Figure 3.24), it is possible to set no limit on the space allocated to the shadows. The script supports this as well by using the Unlimited keyword from the command line:

 1:   C:\>WMIDiskSvc.wsf D: /Action:UpdateShadowStorage /MaxSpace:Unlimited 2:   Microsoft (R) Windows Script Host Version 5.6 3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. 4: 5:   Updating maximum space for the shadow volume ... 6:   Maximum space for Shadow Storage successfully updated. 

Actually, the Unlimited keyword sets the MaxSpace property to a value equal to 18446744073709551615 (which corresponds to 2^64 - 1) defined as a constant at line 76 of Sample 3.51.

If we can create and update the Win32_ShadowStorage instances, it is possible to delete a Win32_ShadowStorage instance. The scripting technique is exactly the same as the update process, with the exception that the instance is deleted by invoking the Delete_ method of the SWBemObject object representing the Win32_ShadowStorage instance (see Sample 3.52).

Sample 3.52: Removing a Win32_ShadowStorage instance (Part XII)

start example

 ...: ...: ...: 570: 571:                - Delete -------------------------------------------------------------------------------------------- 572:                If boolDeleteShadowStorage = True Then 573:                   WScript.Echo "Reseting Shadow Storage area on default volume  " & _ 574:                                strWMIDriverLetter & "'." 575: 576:                   Set objWMIAssociatedInstances = objWMIServices.ExecQuery _ 577:                             ("References of {" & _ 578:                             objWMIInstance.Path_.RelPath & _ 579:                             "} Where ResultClass=Win32_ShadowStorage") ...: 582:                   If objWMIAssociatedInstances.Count = 1 Then 583:                      For Each objWMIAssociatedInstance In objWMIAssociatedInstances 584:                          objWMIAssociatedlnstance.Delete_ ...: 586:                      Next 587: 588:                      WScript.Echo "Shadow Storage successfully reset." 589:                   Else 590:                      WScript.Echo "No Shadow Storage other than the default for volume  '" & _ 591:                                   strWMIDriverLetter & "'." 592:                   End If 593:                End If 594:             End If 595:          End If 596:       Next 597:    End If ...: 602:    ]]> 603:    </script> 604:  </job> 605:</package> 

end example

With the Shadow Copy classes, it is possible to perform all tasks available from the user interface and update almost all properties exposed by the user interface (see Figure 3.24). The only setting that is not manageable from WMI is the schedule information.




Leveraging WMI Scripting
Leveraging WMI Scripting: Using Windows Management Instrumentation to Solve Windows Management Problems (HP Technologies)
ISBN: 1555582990
EAN: 2147483647
Year: 2003
Pages: 82
Authors: Alain Lissoir

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net