4.12 Modifying the security descriptor


4.12 Modifying the security descriptor

In the previous sections we have seen how to access a security descriptor on a secured entity and how to decipher the security descriptor. Although we saw some of the command-line parameters to use to update the security descriptor based on deciphering results and various tables, we did not discover the scripting technique to effectively modify the various security descriptor components. The purpose of this section is to explain how the security descriptor modification is coded, based on the parameters given on the command line.

4.12.1 Updating the security descriptor Owner

The scripting technique used to update the Owner property of the security descriptor differs, based on the security descriptor object model used. With the ADSI object model, the owner is nothing other than a single property containing the "Domain\UserID" owner. However, with the WMI object model, the owner is an instance of the Win32_Trustee class and requires some extra logic to create the instance. Sample 4.41 shows the SetSDOwner() function, which includes the script code for the two object models.

Sample 4.41: Updating the security descriptor owner

start example

  .:  .:  .:  8:' ---------------------------------------------------------------------------------------------  9:Function SetSDOwner(strSIDResolutionDC, strUserID, strPassword, _ 10:                    objSD, strTrustee, intSDType) ..: 14:    Select Case intSDType 15:' Here we have an ADSI security descriptor representation 16:           Case cFileViaADSI, _ 17:                cShareViaADSI, _ 18:                cActiveDirectoryViaWMI, cActiveDirectoryViaADSI, _ 19:                cExchange2000MailboxViaWMI, cExchange2000MailboxViaADSI, _ 20:                cExchange2000MailboxViaCDOEXM, _ 21:                cRegistryViaADSI, _ 22:                cWMINameSpaceViaWMI 23: 24:                objSD.Owner = strTrustee 25: 26:' Here we have a WMI security descriptor representation 27:           Case cFileViaWMI, _ 28:                cShareViaWMI 29: 30:                objSD.Owner = CreateTrustee (strTrustee, _ 31:                                            strSIDResolutionDC, _ 32:                                            strUserID, _ 33:                                            strPassword) 34: 35:' Here we can't retrieve a security descriptor via this access method. 36:           Case cRegistryViaWMI, cWMINameSpaceViaADSI 37: 38:    End Select 39: 40:    WScript.Echo "Security descriptor owner updated to '" & strTrustee & "'." 41: 42:    Set SetSDOwner = objSD 43: 44:End Function 

end example

From line 16 through 24, the owner is stored in the Owner property of the ADSI SecurityDescriptor object (line 24). With the ADSI object model, the update of the security descriptor owner is pretty straightforward, since it assigns a literal string to the Owner property.

To update the security descriptor owner with the WMI object model (lines 27 through 33), the script must first create an instance of the Win32_ Trustee class. This instance is created in the CreateTrustee() function (lines 30 through 33). The CreateTrustee() function is shown in Sample 4.42.

Sample 4.42: Creating a Win32_Trustee instance

start example

  .:  .:  .:  8:' ---------------------------------------------------------------------------------------------  9:Function CreateTrustee (strTrustee, strSIDResolutionDC, strUserID, strPassword) ..: 17:    objWMILocator.Security_.AuthenticationLevel = wbemAuthenticationLevelDefault 18:    objWMILocator.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate 19: 20:    Set objWMIServices = objWMILocator.ConnectServer(strSIDResolutionDC, ""Root\CIMv2"", _ 21:                                                     strUserID, strPassword) ..: 24:    Set objTrustee = objWMIServices.Get("Win32_Trustee").SpawnInstance_() 25: 26:    objTrustee.Domain = ExtractUserDomain (strTrustee) 27:    objTrustee.Name = ExtractUserID (strTrustee) 28: 29:    Set objWMIInstances = objWMIServices.ExecQuery ("Select SID From Win32_Account Where " & _ 30:                                                    "Name='" & objTrustee.Name & "'") ..: 33:    If objWMIInstances.Count = 1 Then 34:    For Each objWMIInstance In objWMIInstances 35:           objTrustee.SIDString = objWMIInstance.SID 36: 37:           Set objSID = objWMIServices.Get("Win32_SID.SID='" & objWMIInstance.SID & "'") 38: 39:           objTrustee.SID = objSID.BinaryRepresentation 40:           objTrustee.SidLength = objSID.SidLength ..: 43:       Next 44:    Else 45:       WScript.Echo "WMI Trustee '" & strTrustee & "' not found on SIDResolutionDC '" & _ 46:                     strSIDResolutionDC & "'." 47:       WScript.Quit (1) 48:    End If ..: 54:    Set CreateTrustee = objTrustee ..: 58:End Function 

end example

This function is slightly more complex, because an instance of the Win32_Trustee class requires the SID of the user. Because the SID of the user must be resolved against the domain hosting that user, the CreateTrustee() function requires some extra parameters:

  • Trustee: This parameter contains the "Domain\UserID" for which the Win32_Trustee must be created.

  • SIDResolutionDC: This parameter contains the Fully Qualified Domain Name (FQDN) of the domain controller to be used for the SID resolution. It should be a domain controller hosting the domain name given in the trustee. By default, if no SIDResolutionDC is given, the localhost is used. If the script is executed on a system not hosting the trustee in its local SAM (or domain if it is a domain controller), the /SIDResolutionDC parameter must be given. In such a case, it must be the FQDN of the domain controller able to resolve the SID for the specified "Domain\UserID." If the trustee could not be resolved to a SID, the Win32_Trustee instance creation will fail. So, make sure that the selected CIM repository (the default one or the one specified by the /SIDResolutionDC switch) always knows the passed "UserID" for the associated "Domain." Note that when the security descriptor is represented in the ADSI object model, the SID resolution is performed inside the ADSI COM object managing the trustee, which makes the task a little bit easier, but this requires that the workstation is well connected to the right domain to resolve the trustee (directly or via trusts).

  • UserID: This parameter is the UserID that WMI uses for the WMI remote connection. It corresponds to the UserID given with the /User switch. If the switch is not specified, the security context of the user executing the script is used to perform the WMI connection to the SIDResolutionDC. In such a case, you must make sure that this user has access, via WMI, to the required system in the Root\CIMv2 namespace.

  • Password: This parameter is the password to be used with the UserID performing the WMI remote connection.

From line 17 through 21, the script performs a WMI connection to resolve the trustee to a SID. Once completed, a new instance of the Win32_Trustee class is created (line 24). Next, the domain name (line 26) and the user name (line 27) of the trustee are assigned to the corresponding Win32_Trustee class properties. To find the SID corresponding to the user name, the script performs a WQL query (lines 29 and 30). If there is one valid response from the WQL query (line 33), the result is enumerated (lines 34 through 43), and the string representation of the SID is saved in the Win32_Trustee instance (line 35). In case of a SID resolution problem, the script displays an error message and stops its execution (lines 44 through 48).

Because a Win32_Trustee instance also requires a binary representation of the SID, lines 37 through 40 retrieve some extra SID information with another WQL query (line 37). This query is based on the Win32_SID class, which uses the SID string representation as one of its properties. Once found, the script assigns the remaining Win32_Trustee properties with the binary SID information (lines 39 and 40). Next, the CreateTrustee() function returns the Win32_Trustee instance, which is assigned to the Owner property of the Win32_SecurityDescriptor instance at line 30 of Sample 4.41.

To produce the result shown in Figure 4.33, the command line to use to update the security descriptor owner is as follows:

 1: C:\>WMIManageSD.Wsf /ADObject:"CN=LISSOIR Alain,CN=Users,DC=LissWare,DC=Net" 2:                    /Owner:LissWareNET\Alain.Lissoir /ADSI+ 

click to expand
Figure 4.33: An Active Directory security descriptor owner.

4.12.2 Updating the security descriptor Group

The logic used to update the Group property is the same as that used to update the Owner property (see Sample 4.43). Via ADSI, the Group property is directly assigned with the "Domain\Group" value (line 24). Via WMI, Sample 4.43 makes use of the CreateTrustee() function previously explained (see Sample 4.42).

Sample 4.43: Updating the security descriptor group

start example

  .:  .:  .:  8:' ---------------------------------------------------------------------------------------------  9:Function SetSDGroup(strSIDResolutionDC, strUserID, strPassword, _ 10:                    objSD, strTrustee, intSDType) ..: 14:    Select Case intSDType 15:' Here we have an ADSI security descriptor representation 16:           Case cFileViaADSI, _ 17:                cShareViaADSI, _ 18:                cActiveDirectoryViaWMI, cActiveDirectoryViaADSI, _ 19:                cExchange2000MailboxViaWMI, cExchange2000MailboxViaADSI, _ 20:                cExchange2000MailboxViaCDOEXM, _ 21:                cRegistryViaADSI, _ 22:                cWMINameSpaceViaWMI 23: 24:                objSD.Group = strTrustee 25: 26:' Here we have a WMI security descriptor representation 27:           Case cFileViaWMI, _ 28:                cShareViaWMI 29: 30:                objSD.Group = CreateTrustee (strTrustee, _ 31:                                            strSIDResolutionDC, _ 32:                                            strUserID, _ 33:                                            strPassword) 34: 35:' Here we can't retrieve a security descriptor via this access method. 36:           Case cRegistryViaWMI, _ 37:                cWMINameSpaceViaADSI 38: 39:    End Select 40: 41:    WScript.Echo "Security descriptor group updated to '" & strTrustee & "'." 42: 43:    Set SetSDGroup = objSD 44: 45:End Function 

end example

4.12.3 Updating the security descriptor Control Flags

The security descriptor Control Flags property contains several flags (see Table 4.8, "The security descriptor Control Flags values"). However, the script does not allow the modification of all flags, since the script already manages some of them internally. The flags that can be specified from the command line are:

  • SE_DACL_PROTECTED

  • SE_SACL_PROTECTED

  • SE_DACL_AUTO_INHERIT_REQ

  • SE_SACL_AUTO_INHERIT_REQ

As shown in Table 4.8, these flags are controlling the security descriptor behavior regarding the inherited ACE. For instance, if the security descriptor is protected against inherited ACE, which means that inherited ACE is not inherited by the security descriptor (SE_DACL_PROTECTED=ON), we have a configuration similar to the one shown in Figure 4.34 (right pane). Note that the user interface check box is unchecked when the SE_DACL_PROTECTED flag is turned ON.

click to expand
Figure 4.34: The Control Flags configuration.

During a Control Flags modification (SE_DACL_PROTECTED=OFF to SE_DACL_PROTECTED=ON, or as shown in Figure 4.34, left and right panes) by script via ADSI or WMI, the inherited ACEs are not inherited anymore and become directly applied ACE (or noninherited ACE).

The next command line turns to ON the SE_DACL_PROTECTED flag, since it is currently turned OFF (left pane of Figure 4.34):

 1:   C:\>WMIManageSD.Wsf /FileSystem:C:\MyDirectory /SDControls:SE_DACL_PROTECTED 2:   Microsoft (R) Windows Script Host Version 5.6 3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. 4: 5:   Reading File or Folder security descriptor via WMI from 'C:\MyDirectory'. 6:   ACL inheritance protection is OFF and will be turned ON. 7:   Setting File or Folder security descriptor via WMI to 'C:\MyDirectory'. 

Now the SE_DACL_PROTECTED is turned ON (right pane of Figure 4.34).

If the script is run a second time with the same parameters, the bit corresponding to the SE_DACL_PROTECTED flag is switched back to OFF.

 1:   C:\>WMIManageSD.Wsf /FileSystem:C:\MyDirectory /SDControls:SE_DACL_PROTECTED 2:   Microsoft (R) Windows Script Host Version 5.6 3:   Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. 4: 5:   Reading File or Folder security descriptor via WMI from 'C:\MyDirectory'. 6:   ACL inheritance protection is ON and will be turned OFF. 7:   Setting File or Folder security descriptor via WMI to 'C:\MyDirectory'. 

As a consequence (see Figure 4.35), the inherited ACEs are added to the noninherited ACEs.

click to expand
Figure 4.35: The effect of resetting the SE_DACL_PROTECTED flag twice.

The manipulation of all Control Flags bits is basically the same. Whenever the security descriptor is represented in the ADSI or WMI object models, Sample 4.44 uses the same logic as previously. Because the Control Flags property is named Control in the ADSI object model and named ControlFlags in the WMI object model, the script code must take the object model used into consideration to assign the new value, despite the fact the logic is the same (lines 23 through 27 for the ADSI object model, lines 35 through 39 for the WMI object model).

Sample 4.44: Updating the security descriptor control flags

start example

 .: .: .: 8:' --------------------------------------------------------------------------------------------- 9:Function SetSDControlFlags(objSD, intSDControlFlags, intSDType) ..: 13:   Select Case intSDType 14:' Here we have an ADSI security descriptor representation 15:           Case cFileViaADSI, _ 16:           cShareViaADSI, _ 17:           cActiveDirectoryViaWMI, cActiveDirectoryViaADSI, _ 18:           cExchange2000MailboxViaWMI, cExchange2000MailboxViaADSI, _ 19:           cExchange2000MailboxViaCDOEXM, _ 20:           cRegistryViaADSI, _ 21:           cWMINameSpaceViaWMI 22: 23:           If (objSD.Control And intSDControlFlags) = intSDControlFlags Then 24:              WScript.Echo "ACL inheritance protection is OFF and will be turned ON." 25:           Else 26:              WScript.Echo "ACL inheritance protection is ON and will be turned OFF." 27:           End If 28: 29:           objSD.Control = objSD.Control Xor intSDControlFlags 30: 31:' Here we have a WMI security descriptor representation 32:           Case cFileViaWMI, _ 33:                cShareViaWMI 34: 35:                If (objSD.ControlFlags And intSDControlFlags) = intSDControlFlags Then 36:                   WScript.Echo "ACL inheritance protection is OFF and will be turned ON." 37:                Else 38:                   WScript.Echo "ACL inheritance protection is ON and will be turned OFF." 39:                End If 40: 41:                objSD.ControlFlags = objSD.ControlFlags Xor intSDControlFlags 42: 43:' Here we can't retrieve a security descriptor via this access method. 44:           Case cRegistryViaWMI, _ 45:                cWMINameSpaceViaADSI 46: 47:    End Select 48: 49:    Set SetSDControlFlags = objSD 50: 51:End Function 

end example

4.12.4 Adding an ACE

To manipulate ACEs in security descriptors, it is necessary to look at the ACL. Since ACLs are represented differently in the ADSI and WMI object models, the script must handle them differently. The next two sections will explain the logic used for the ACE additions in the ADSI and WMI object models, respectively. The code snippets are direct applications of sections 4.11.3 ("Deciphering the Access Control Lists") and 4.11.4 ("Deciphering the Access Control Entries") as examples of configuring ACEs to make use of the /AddACE+ switch.

The AddACE() function is executed when the /AddACE+ switch is specified on the command line. For example:

 C:\>WMIManageSD.Wsf /WMINameSpace:Root\MyNameSpace                     /Trustee:BUILTIN\Administrators /ACEType:ACCESS_ALLOWED_ACE_TYPE                     /ACEMask:WBEM_ENABLE,                              WBEM_METHOD_EXECUTE,                              WBEM_WRITE_PROVIDER,                              WBEM_REMOTE_ACCESS                     /ACEFlags:CONTAINER_INHERIT_ACE                     /AddAce+ 

4.12.4.1 Adding an ACE in the ADSI object model

The AddACE() function shown in Samples 4.45 and 4.46 implements the logic to add ACEs in the ADSI and WMI object models. The function is divided into two parts: one for the ADSI object model (Sample 4.45) and the second one (Sample 4.46) for the WMI object model. Because the new ACE is built and added in the function, the function exposes several parameters:

  • objWMIServices: This parameter is an SWBemServices object representing the WMI connection to the local CIM repository. This parameter is only used to create a new instance of the Win32_ACE class when the security descriptor is represented in the WMI object model. For the ADSI object model, this parameter can be set to Null.

  • SIDResolutionDC, UserID, and Password: These parameters are the ones used by the CreateTrustee() function (Sample 4.42, "Creating a Win32_Trustee instance"). They are only used when the security descriptor is represented in the WMI object model. For the ADSI object model, these parameters can be set to Null (see Sample 4.4, "Connecting to files and folders with ADSI [Part II]," line 591).

  • objSD: This parameter is the structural representation of the security descriptor in the ADSI or WMI object model.

  • Trustee, ACEType, AccessMask, ACEFlags, ACLType, ObjectType, and InheritedObjectType: These parameters are the new ACE properties. These parameters are used both in the ADSI and WMI object models. Note that the ObjectType and InheritedObjectType parameters are only used when the security descriptor is an Active Directory security descriptor.

  • SDType: This parameter determines the security descriptor access method, which implicitly determines the object model.

Sample 4.45: Adding ACE in the ADSI object model (Part I)

start example

  .:  .:  .:  8:' ---------------------------------------------------------------------------------------------  9:Function AddACE(objWMIServices, strSIDResolutionDC, strUserID, strPassword, _ 10:            objSD, strTrustee, intACEType, intAccessMask, intACEFlags, intACLType, _ 11:            strObjectType, strInheritedObjectType, intSDType) ..: 21:    Select Case intSDType 22:' Here we have an ADSI security descriptor representation 23:           Case cFileViaADSI, _ 24:                cShareViaADSI, _ 25:                cActiveDirectoryViaWMI, cActiveDirectoryViaADSI, _ 26:                cExchange2000MailboxViaWMI, cExchange2000MailboxViaADSI, _ 27:                cExchange2000MailboxViaCDOEXM, _ 28:                cRegistryViaADSI, _ 29:                cWMINameSpaceViaWMI 30: 31:                Select Case intACLType 32:                       Case cDACL 33:                            Set objACL = objSD.DiscretionaryAcl 34:                       Case cSACL 35:                            Set objACL = objSD.SystemAcl 36:                       Case Else 37:                            Exit Function 38:                End Select 39: 40:                Set objNewACE = CreateObject("AccessControlEntry") 41: 42:                objNewACE.Trustee = strTrustee 43:                objNewACE.AceType = intACEType 44:                objNewACE.AccessMask = intAccessMask 45:                objNewACE.AceFlags = intACEFlags 46: 47:                Select Case intSDType 48:                       Case cActiveDirectoryViaWMI, cActiveDirectoryViaADSI, _ 49: 50:                       If Len (strObjectType) Then 51:                          objNewACE.ObjectType = strObjectType 52:                          objNewACE.Flags = objNewACE.Flags Or _ 53:                                            ADS_FLAG_OBJECT_TYPE_PRESENT 54:                       End If 55: 56:                       If Len (strInheritedObjectType) Then 57:                               objNewACE.InheritedObjectType = strInheritedObjectType 58:                               objNewACE.Flags = objNewACE.Flags Or _ 59:                                                 ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT 60:                            End If 61: 62:                       Case cFileViaADSI, _ 63:                            cExchange2000MailboxViaWMI, cExchange2000MailboxViaADSI, _ 64:                            cExchange2000MailboxViaCDOEXM, _ 65:                            cRegistryViaADSI, _ 66:                            cWMINameSpaceViaWMI 67: 68:                End Select 69: 70:                objACL.AddAce objNewACE 71: 72:                Select Case intACLType 73:                       Case cDACL 74:                            objSD.DiscretionaryAcl = objACL 75:                            objSD.Control = objSD.Control Or SE_DACL_PRESENT 76:                       Case cSACL 77:                            objSD.SystemAcl = objACL 78:                            objSD.Control = objSD.Control Or SE_SACL_PRESENT 79:                End Select 80: 81:                Wscript.Echo "Trustee '" & strTrustee & _ 82:                             "' has been added to security descriptor." ..: ..: ..: 

end example

Sample 4.46: Adding ACE in the WMI object model (Part II)

start example

  ..:  ..:  ..:  87:  88:' Here we have a WMI security descriptor representation  89:           Case cFileViaWMI, _  90:                cShareViaWMI  91:  92:                Select Case intACLType  93:                       Case cDACL  94:                            arrayACL = objSD.DACL  95:                       Case cSACL  96:                            arrayACL = objSD.SACL  97:                       Case Else  98:                            Exit Function  99:                End Select 100: 101:                Set objNewACE = objWMIServices.Get("Win32_ACE").SpawnInstance_() 102: 103:                objNewACE.Trustee = CreateTrustee (strTrustee, _ 104:                                                   strSIDResolutionDC, _ 105:                                                   strUserID, _ 106:                                                   strPassword) 107:                objNewACE.AceType = intACEType 108:                objNewACE.AccessMask = intAccessMask 109:                objNewACE.AceFlags = intACEFlags 110: 111:                ' If ACL already contains some ACE, make sure we don't destroy them ... 112:                If IsArray (arrayACL) Then 113:                   intIndice = UBound(arrayACL) 114:                   ReDim Preserve arrayACL (intIndice + 1) 115:                   Set arrayACL (intIndice + 1) = objNewACE 116:                Else 117:                   ReDim arrayACL (0) 118:                   Set arrayACL (0) = objNewACE 119:                End If ...: 123:                Select Case intACLType 124:                       Case cDACL 125:                            objSD.DACL = arrayACL 126:                            objSD.ControlFlags = objSD.ControlFlags Or SE_DACL_PRESENT 127:                       Case cSACL 128:                            objSD.SACL = arrayACL 129:                            objSD.ControlFlags = objSD.ControlFlags Or SE_SACL_PRESENT 130:                End Select 131: 132:                Wscript.Echo "Trustee '" & strTrustee & _ 133:                             "' has been added to security descriptor." 134: 135:' Here we do not have a security descriptor available via these access methods. 136:           Case cRegistryViaWMI, cWMINameSpaceViaADSI 137: 138:    End Select ...: 142:End Function 

end example

Sample 4.45 starts by extracting the ACL from the ADSI security descriptor. Based on the ACLType parameter, the Discretionary ACL or the System ACL is extracted (lines 31 through 38). Next, it builds the new ACE by creating a new instance of the AccessControlEntry ADSI object (line 40) and assigns the ACE properties (lines 42 through 45). If the security descriptor is an Active Directory security descriptor, then the ObjectType and/or the InheritedObjectType parameters are assigned (lines 47 through 68). These two parameters contain GUID numbers, as explained in sections 4.11.4.5.3.1 ("Understanding the ACE ObjectType property") and 4.11.4.5.3.2 ("Understanding the ACE InheritedObjectType property"). Because this portion of the script manages the ADSI security descriptor representation, it must set the ACE FlagType property of the ADSI AccessControlEntry object to save the GUID values back to the security descriptor.

Next, the new ACE is added to the ACL (line 70), and the ACL is stored back in the security descriptor according to the ACLType parameter (lines 72 through 79).

4.12.4.2 Adding an ACE in the WMI object model

In the WMI object model, the overall logic is exactly the same as the ADSI object model. However, instead of manipulating the ACE from a collection (ACL), Sample 4.46 manipulates an array containing ACEs. As before, it extracts the ACL from the WMI security descriptor according to the ACLType parameter (lines 92 through 99). Next, it creates a new ACE with the use of the SWBemServices object (line 101) and assigns the various ACE properties (lines 103 through 109). Note the use of the CreateTrustee() function (Sample 4.42, "Creating a Win32_Trustee instance") to assign the WMI ACE Trustee property. Once completed, the new ACE is added to the ACL (lines 111 through 119). Next, the ACL is stored back to the security descriptor according to the ACLType parameter (lines 123 through 130).

4.12.5 Removing an ACE

Since the script must manage ACLs in two different object models to remove an ACE from an ACL, the coding technique will be different. Moreover, the logic to remove an ACE from an ACL is totally different from ACE additions. The next two sections cover this functionality in the DelACE() function with the ADSI object model (Sample 4.47) and the WMI object model (Sample 4.48).

Sample 4.47: Removing ACE in the ADSI object model (Part I)

start example

   .:   .:   .:   8:' ---------------------------------------------------------------------------------------------   9:Function DelACE(objWMIServices, strSIDResolutionDC, strUserID, strPassword, _  10:                objSD, strTrustee, intACLType, intSDType)  ..:  ..:  ..:  26:    Select Case intSDType  27:' Here we have an ADSI security descriptor representation  28:           Case cFileViaADSI, _  29:                cShareViaADSI, _  30:                cActiveDirectoryViaWMI, cActiveDirectoryViaADSI, _  31:                cExchange2000MailboxViaWMI, cExchange2000MailboxViaADSI, _  32:                cExchange2000MailboxViaCDOEXM, _  33:                cRegistryViaADSI, _  34:                cWMINameSpaceViaWMI  35:  36:                Select Case intACLType  37:                       Case cDACL  38:                            Set objACL = objSD.DiscretionaryAcl  39:                       Case cSACL  40:                            Set objACL = objSD.SystemAcl  41:                       Case Else  42:                            Exit Function  43:                End Select  44:  45:                ' Only proceed an ACE removal, if there is at least one available ...  46:                If objACL.AceCount Then  47:                   If Ucase(strTrustee) = "REMOVE_ALL_ACE" Then  48:                      For Each objACE In objACL  49:                          objACL.RemoveAce (objACE)  50:                      Next  51:  52:                      If objACL.AceCount = 0 Then  53:                         Select Case intACLType  54:                                Case cDACL  55:                                     Set objNewACE = CreateObject("AccessControlEntry")  56:  57:                                     objNewACE.Trustee = "Everyone"  58:                                     objNewACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED  59:                                     objNewACE.AccessMask = ADS_RIGHT_GENERIC_ALL  60:                                     objNewACE.AceFlags = CONTAINER_INHERIT_ACE Or _  61:                                                          OBJECT_INHERIT_ACE  62:  63:                                     Wscript.Echo "All ACE removed, Trustee '" & _  64:                                             objNewACE.Trustee & _  65:                                             "' (Full Control) has been created."  66:  67:                                objACL.AddAce objNewACE  68:  69:                                objSD.Control = objSD.Control Or _  70:                                                SE_DACL_PRESENT  ..:  73:                                Case cSACL  74:                                     objSD.Control = objSD.Control And _  75:                                                     (NOT SE_SACL_PRESENT)  76:                           End Select  77:                        End If  78:  79:                        boolRemoveAce = True  80:                     Else  81:                        For Each objACE In objACL  82:                            If Ucase(objACE.Trustee) = Ucase(strTrustee) Then  83:                               If (objACE.AceFlags And INHERITED_ACE) = INHERITED_ACE Then  84:                                  Wscript.Echo "Trustee '" & objACE.Trustee & _  85:                                               "' is inherited and therefore can't be removed."  86:                            Else  87:                               Wscript.Echo "Trustee '" & strTrustee & _  88:                                         "' has been removed from security descriptor."  89:                               objACL.RemoveAce (objACE)  90:  91:                               If objACL.AceCount = 0 Then  92:                                  Select Case intACLType  93:                                         Case cDACL  94:                                           Set objNewACE = CreateObject("AccessControlEntry")  95:  96:                                           objNewACE.Trustee = "Everyone"  97:                                           objNewACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED  98:                                           objNewACE.AccessMask = ADS_RIGHT_GENERIC_ALL  99:                                           objNewACE.AceFlags = CONTAINER_INHERIT_ACE Or _ 100:                                                                OBJECT_INHERIT_ACE 101: 102:                                           Wscript.Echo "All ACE removed, Trustee '" & _ 103:                                                        objNewACE.Trustee & _ 104:                                                        "' (Full Control) has been created." 105: 106:                                           objACL.AddAce objNewACE 107: 108:                                           objSD.Control = objSD.Control Or _ 109:                                                           SE_DACL_PRESENT ...: 112:                                         Case cSACL 113:                                           objSD.Control = objSD.Control And _ 114:                                                           (NOT SE_SACL_PRESENT) 115:                                  End Select 116:                               End If 117: 118:                               boolRemoveAce = True 119:                            End If 120:                         End If 121:                     Next 122:                  End If 123: 124:                  If objACL.AceCount = 0 Then 125:                     Wscript.Echo "All ACE removed." 126:                   End If 127: 128:                   Select Case intACLType 129:                          Case cDACL 130:                               objSD.DiscretionaryAcl = objACL 131:                          Case cSACL 132:                               objSD.SystemAcl = objACL 133:                   End Select 134:                Else 135:                   WScript.Echo "No existing ACE to remove." 136:                   WScript.Quit(1) 137:                End If ...: ...: ...: 

end example

Sample 4.48: Removing ACE in the WMI object model (Part II)

start example

 ...: ...: ...: 140: 141:' Here we have a WMI security descriptor representation 142:           Case cFileViaWMI, _ 143:                cShareViaWMI 144: 145:                Select Case intACLType 146:                       Case cDACL 147:                            arrayACL = objSD.DACL 148:                       Case cSACL 149:                            arrayACL = objSD.SACL 150:                       Case Else 151:                            Exit Function 152:                End Select 153: 154:                ' Only proceed an ACE removal, if there is at least one available ... 155:                If IsArray(arrayACL) Then 156:                   If UCase (strTrustee) = "REMOVE_ALL_ACE" Then 157:                      If UBound(arrayACL) = 0 Then ...: ...: ...: 158:              Select Case intACLType 159:                     Case cDACL 160:                          Set objNewACE = objWMIServices.Get("Win32_ACE").SpawnInstance_() 161: 162:                          objNewACE.Trustee = CreateTrustee ("Everyone", _ 163:                                                             strSIDResolutionDC, _ 164:                                                             strUserID, _ 165:                                                             strPassword) 166:                          objNewACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED 167:                          objNewACE.AccessMask = ADS_RIGHT_GENERIC_ALL 168:                          objNewACE.AceFlags = CONTAINER_INHERIT_ACE Or _ 169:                                               OBJECT_INHERIT_ACE 170: 171:                          Wscript.Echo "All ACE removed, Trustee 'Everyone' " & _ 172:                                       "(Full Control) has been created." 173: 174:                          ReDim arrayNewACL (0) 175:                          Set arrayNewACL (0) = objNewACE 176: 177:                          objSD.ControlFlags = objSD.ControlFlags Or _ 178:                                               SE_DACL_PRESENT ...: 181:                     Case cSACL 182:                          objSD.ControlFlags = objSD.ControlFlags And _ 183:                                               (NOT SE_SACL_PRESENT) 184:              End Select ...: ...: ...: 185:                      End If 186: 187:                      boolRemoveAce = True 188:                   Else 189: 190:                      strDomainName = ExtractUserDomain (strTrustee) 191:                      strUserName = ExtractUserID (strTrustee) 192: 193:                      intIndice2 = 0 194:                      For intIndice1 = 0 To UBound(arrayACL) 195:                          Set objACE = arrayACL(intIndice1) 196:                          Set objTrustee = objACE.Trustee 197:                          If Ucase(objTrustee.Name) = Ucase(strUserName) Then 198:                             If (objACE.AceFlags And INHERITED_ACE) = INHERITED_ACE Then 199:                                Wscript.Echo "Trustee '" & strTrustee & _ 200:                                             "' is inherited and therefore can't be removed." 201: 202:                                ReDim Preserve arrayNewACL(intIndice2) 203:                                Set arrayNewACL(intIndice2) = objACE 204:                                intIndice2 = intIndice2 + 1 205:                             Else 206:                                Wscript.Echo "Trustee '" & strTrustee & _ 207:                                             "' has been removed from security descriptor." 208: 209:                                If UBound(arrayACL) = 0 Then ...: ...: ...: 210:              Select Case intACLType 211:                     Case cDACL 212:                          Set objNewACE = objWMIServices.Get("Win32_ACE").SpawnInstance_() 213: 214:                          objNewACE.Trustee = CreateTrustee ("Everyone", 215:                                                             strSIDResolutionDC, _ 216:                                                             strUserID, _ 217:                                                             strPassword) 218:                          objNewACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED 219:                          objNewACE.AccessMask = ADS_RIGHT_GENERIC_ALL 220:                          objNewACE.AceFlags = CONTAINER_INHERIT_ACE Or _ 221:                                               OBJECT_INHERIT_ACE 222: 223:                          Wscript.Echo "All ACE removed,Trustee 'Everyone'" & _ 224:                                      "(Full Control) has been created." 225: 226:                         ReDim arrayNewACL (0) 227:                         Set arrayNewACL (0) = objNewACE 228: 229:                         objSD.ControlFlags = objSD.ControlFlags Or _ 230:                                              SE_DACL_PRESENT ...: 233:                    Case cSACL 234:                         objSD.ControlFlags = objSD.ControlFlags And _ 235:                                              (NOT SE_SACL_PRESENT) 236:             End Select ...: ...: ...: 237:                               End If 238: 239:                               boolRemoveAce = True 240:                            End If 241:                         Else 242:                            ReDim Preserve arrayNewACL(intIndice2) 243:                            Set arrayNewACL(intIndice2) = objACE 244:                            intIndice2 = intIndice2 + 1 245:                         End If ...: 249:                     Next 250:                  End If 251: 252:                  intAceCount = Ubound(arrayNewACL) 253:                  If Err.Number = 9 Then 254:                     Err.Clear 255: 256:                     Wscript.Echo "All ACE removed." 257: 258:                     Select Case intACLType 259:                            Case cDACL 260:                                 objSD.DACL = Null 261:                            Case cSACL 262:                                 objSD.SACL = Null 263:                     End Select 264:                  Else 265:                     Select Case intACLType 266:                            Case cDACL 267:                                 objSD.DACL = arrayNewACL 268:                            Case cSACL 269:                                 objSD.SACL = arrayNewACL 270:                     End Select 271:                  End If 272:               Else 273:                  WScript.Echo "No existing ACE to remove." 274:                  WScript.Quit(1) 275:               End If 276: 277:' Here we can't retrieve a security descriptor via this access method. 278:           Case cRegistryViaWMI, _ 279:                cWMINameSpaceViaADSI 280: 281:    End Select 282: 283:    If boolRemoveAce = False Then 284:       WScript.Echo "WARNING: Implicit ACE for Trustee '" & strTrustee & _ 285:                    "' NOT found in security descriptor." 286:       WScript.Quit(1) 287:    End If 288: 289:    Set DelACE = objSD 290: 291:End Function 

end example

The DelACE() function is executed when the /DelACE+ switch is specified on the command line. For example:

 C:\>WMIManageSD.Wsf /Share:MyDirectory /Trustee:Everyone /DelAce+ 

4.12.5.1 Removing ACE in the ADSI object model

Basically, the DelACE() input parameters are almost the same as the AddACE() parameters. However, the DelACE() function does not require all ACE details. Only the Trustee is necessary. Simply said, the function browses all ACEs in the ACL and removes any ACE that has a matching Trustee. Of course, if a trustee is granted with many different rights (which means that it could exist in many different ACEs), all ACEs matching that trustee will be removed. If a more granular removal technique is required, then the match must be made on more ACE properties than on the Trustee, which will require more command-line parameters not supported by the WMIManageSD.Wsf script in its current version.

Note that it is possible to use a special keyword (REMOVE_ALL_ACE) assigned to the Trustee parameter of the DelACE() function to remove all ACEs present in the ACL. In such a case, after this removal, the script grants the "Everyone" Full Control right to make sure that the object is still accessible. Granting "Everyone" Full Control is equal to suppressing the concept of controlling the access. From a human point of view, this makes sense, but from a computer point of view, removing all access controls means no access at all. That's why this trustee is added. Note that this right is only set for a DACL. In the case of a SACL, no default ACE is created. The ACL of a SACL will be emptied.

Now that we understand the DelACE() function features, let's see how the coding works (see Sample 4.47).

As with the AddACE() function, the DelACE() function first retrieves the DACL or the SACL, based on the ACLType parameter (lines 36 through 43). Once complete, the DelACE() function is divided into two parts for each object model:

  1. Removing all ACEs (lines 47 through 79): This part makes use of the REMOVE_ALL_ACE keyword to remove all available ACEs. The script enumerates all ACEs to remove instead of creating a new ACL (lines 48 through 50). Recreating a new ACL will force the version number of the ACL to be set in the ADSI object model. To keep the logic totally generic, the script keeps the ACL object intact by removing only ACEs. Since the AccessControlList object exposes the RemoveACE method, this makes the coding technique quite easy (line 49). Of course, creating a brand new ACL is also a valid technique. Next, if the ACL is emptied (line 52), the script checks if the ACL comes from a DACL (line 54) or a SACL (line 73). In case of a DACL, a default ACE is created (lines 55 through 70). At lines 69 and 70, the script sets the security descriptor Control Flags according to the DACL presence. At lines 74 and 75, the script sets the SACL presence to OFF in the security descriptor Control Flags, since a default ACE is only created for a DACL. Note that inherited ACEs are not removed by ADSI. They continue to appear as inherited ACEs. If they must be removed, the SE_DACL_PROTECTED flag must be first set to ON, or the parent object defining the inherited ACE must be modified accordingly.

  2. Removing a specific ACE based on the Trustee name (lines 81 through 121): In such a case, the script enumerates all ACEs (lines 81 through 121), but if the Trustee DelACE() function parameter matches the Trustee property of an examined ACE (line 82), then the ACE is removed (line 89). Note that inherited ACEs are not removed (lines 83 through 85). Once the ACE is removed, and if the DACL does not contain any ACE, a default ACE based on the "Everyone" trustee is created (lines 93 through 109), as done in the first part of the code. Next, the security descriptor Control Flags is set accordingly (lines 108 and 109, lines 113 and 114).

4.12.5.2 Removing ACE in the WMI object model

The ACE removal in the WMI object model follows the same logic as the ACE removal in the ADSI object model. Of course, as mentioned previously, instead of manipulating a collection of ACEs in an ACL, Sample 4.48 manipulates items in an array, where the array represents the ACL and array items represent ACEs.

Although the overall logic used in the WMI object model is the same as the logic used in the ADSI object model, in the coding details there are some important differences. From a global standpoint, we still have two parts with the same purpose as for the ADSI object model:

  1. Removing all ACEs (lines 156 through 187)

  2. Removing a specific ACE based on the Trustee name (lines 188 through 250)

Because the ACL in the WMI object model is represented by an array, instead of manipulating the original array content another array is populated with the ACEs that are not removed. When all ACEs are removed in a DACL, this new array is initialized with the default ACE based on the "Everyone" trustee (lines 160 through 180). When removing a specific ACE, the inherited ACEs are not removed and are copied to the new array (lines 198 through 204). The same applies for ACEs that do not match the Trustee DelACE() function input parameter (lines 242 through 244). Basically, when an ACE is removed from the original ACL, it is not copied to the new array. Before completion, the script checks if the new array is initialized with some ACEs (line 252). If there is no ACE, the UBound() function returns an error (line 253). In such a case, the DACL or the SACL (based on the ACLType parameter) is set to Null (lines 258 through 270). If the new array is initialized with one or more ACEs, no error is returned and the DACL or SACL property is assigned with this new array (lines 265 through 270).

4.12.6 Reordering ACEs

When ACEs are added or removed from an ACL, it is quite important to properly reorder ACEs, because, in some cases, adding an ACE at the top of an ACL could create undesired security access. This ordering is also called the canonical order. When editing permissions with the ACL editor (i.e., from the Windows Explorer), it is important to note that the editor saves the updated rights in canonical order. Therefore, to avoid any security troubles, it is important to perform the same ordering from the WMIManageSD.Wsf script. The ACEs in an ACL must be sorted into these five groups:

  • Access-denied ACEs, which apply to the object itself

  • Access-denied ACEs, which apply to a child of the object, such as a property set or property

  • Access-allowed ACEs, which apply to the object itself

  • Access-allowed ACEs, which apply to a child of the object, such as a property set or property

  • All inherited ACEs

The ADSI and WMI object models do not support a method to properly order ACEs in an ACL. This implies that a customized logic must handle the ACE ordering. Sample 4.49 implements the logic in the ADSI object model, while Sample 4.50 implements the logic in the WMI object model. Both samples uses a logic inspired from Microsoft Knowledge Base article Q269159.

Sample 4.49: Reordering ACE in the ADSI object model (Part I)

start example

   .:   .:   .:   8:' ---------------------------------------------------------------------------------------------   9:Function ReOrderACE(objWMIServices, objSD, intSDType) ..:  39:    Select Case intSDType  40:' Here we have an ADSI security descriptor representation  41:           Case cFileViaADSI, _  42:                cShareViaADSI, _  43:                cActiveDirectoryViaWMI, cActiveDirectoryViaADSI, _  44:                cExchange2000MailboxViaWMI, cExchange2000MailboxViaADSI, _  45:                cExchange2000MailboxViaCDOEXM, _  46:                cRegistryViaADSI, _  47:                cWMINameSpaceViaWMI  48:  49:                ' Only the DACL is re-ordered  50:                Set objACL = objSD.DiscretionaryAcl  51:  52:                If objACL.AceCount Then  53:                   Set objNewACL = CreateObject("AccessControlList")  54:                   Set objImplicitDenyACL = CreateObject("AccessControlList")  55:                   Set objImplicitDenyObjectACL = CreateObject("AccessControlList")  56:                   Set objImplicitAllowACL = CreateObject("AccessControlList")  57:                   Set objImplicitAllowObjectACL = CreateObject("AccessControlList")  58:                   Set objInheritedACL = CreateObject("AccessControlList")  59:  60:                   For Each objACE In objACL  61:                       If ((objACE.AceFlags And ADS_ACEFLAG_INHERITED_ACE) = _  62:                                                ADS_ACEFLAG_INHERITED_ACE) Or _  63:                          ((objACE.AceFlags And INHERITED_ACE) = INHERITED_ACE) Then  64:                          objInheritedACL.AddAce objACE  65:                       Else  66:                          Select Case objACE.AceType  67:                                 Case ADS_ACETYPE_ACCESS_DENIED,ACCESS_DENIED_ACE_TYPE  68:                                      objImplicitDenyACL.AddAce objACE  69:                                 Case ADS_ACETYPE_ACCESS_DENIED_OBJECT  70:                                      objImplicitDenyObjectACL.AddAce objACE  71:                                 Case ADS_ACETYPE_ACCESS_ALLOWED,ACCESS_ALLOWED_ACE_TYPE  72:                                      objImplicitAllowACL.AddAce objACE  73:                                 Case ADS_ACETYPE_ACCESS_ALLOWED_OBJECT  74:                                      objImplicitAllowObjectACL.AddAce objACE  75:                                 Case Else  76:                                      ' Bad objACE  77:                          End Select  78:                       End If  79:                   Next  80:  81:                   ' Implicit Deny ACE.  82:                   For Each objACE In objImplicitDenyACL  83:                       objNewACL.AddAce objACE  84:                   Next  85:  86:                   ' Implicit Deny ACE Objects.  87:                   For Each objACE In objImplicitDenyObjectACL  88:                       objNewACL.AddAce objACE  89:                   Next  90:  91:                   ' Implicit Allow ACE.  92:                   For Each objACE In objImplicitAllowACL  93:                       objNewACL.AddAce objACE  94:                   Next  95:  96:                   ' Implicit Allow ACE Objects.  97:                   For Each objACE In objImplicitAllowObjectACL  98:                       objNewACL.AddAce objACE  99:                   Next 100: 101:                   ' Inherited ACE. 102:                   For Each objACE In objInheritedACL 103:                       objNewACL.AddAce objACE 104:                   Next 105: 106:                   objNewACL.AclRevision = objACL.AclRevision 107: 108:                   objSD.DiscretionaryAcl = objNewACL ...: 118:                End If 119: ...: ...: ...: 

end example

Sample 4.50: Reordering ACE in the WMI object model (Part II)

start example

 ...: ...: ...: 119: 120:' Here we have a WMI security descriptor representation 121:           Case cFileViaWMI, _ 122:                cShareViaWMI 123: 124:                ' Only the DACL is re-ordered 125:                arrayACL = objSD.DACL 126: 127:                If IsArray (arrayACL) Then 128:                   For intIndice = 0 To UBound(arrayACL) 129:                       If ((arrayACL(intIndice).AceFlags And ADS_ACEFLAG_INHERITED_ACE) = _ 130:                                                             ADS_ACEFLAG_INHERITED_ACE) Or _ 131:                          ((arrayACL(intIndice).AceFlags And INHERITED_ACE)=INHERITED_ACE) Then 132:                          intInheritedACL = intInheritedACL + 1 133:                          ReDim Preserve arrayInheritedACL(intInheritedACL) 134:                          Set arrayInheritedACL(intInheritedACL) = arrayACL(intIndice) 135:                       Else ...: 136: Select Case arrayACL(intIndice).AceType 137:        Case ADS_ACETYPE_ACCESS_DENIED,ACCESS_DENIED_ACE_TYPE 138:             intImplicitDenyACL = intImplicitDenyACL + 1 139:             ReDim Preserve arrayImplicitDenyACL(intImplicitDenyACL) 140:             Set arrayImplicitDenyACL(intImplicitDenyACL) = arrayACL(intIndice) 141:        Case ADS_ACETYPE_ACCESS_DENIED_OBJECT 142:             intImplicitDenyObjectACL = intImplicitDenyObjectACL + 1 143:             ReDim Preserve arrayImplicitDenyObjectACL(intImplicitDenyObjectACL) 144:             Set arrayImplicitDenyObjectACL(intImplicitDenyObjectACL) = arrayACL(intIndice) 145:        Case ADS_ACETYPE_ACCESS_ALLOWED,ACCESS_ALLOWED_ACE_TYPE 146:             intImplicitAllowACL = intImplicitAllowACL + 1 147:             ReDim Preserve arrayImplicitAllowACL(intImplicitAllowACL) 148:             Set arrayImplicitAllowACL(intImplicitAllowACL) = arrayACL(intIndice) 149:        Case ADS_ACETYPE_ACCESS_ALLOWED_OBJECT 150:             intImplicitAllowObjectACL = intImplicitAllowObjectACL + 1 151:             ReDim Preserve arrayImplicitAllowObjectACL(intImplicitAllowObjectACL) 152:             Set arrayImplicitAllowObjectACL(intImplicitAllowObjectACL) = arrayACL(intIndice) 153:        Case Else 154:             ' Bad ACE 155: End Select ...: 156:                       End If 157:                   Next 158: 159:                   ' Implicit Deny ACE. 160:                   If intImplicitDenyACL Then 161:                      For intIndice = 1 To Ubound(arrayImplicitDenyACL) 162:                          ReDim Preserve arrayNewACL(intNewACL) 163:                          Set arrayNewACL(intNewACL) = arrayImplicitDenyACL(intIndice) 164:                          intNewACL = intNewACL + 1 165:                      Next 166:                   End If 167: 168:                   ' Implicit Deny ACE Objects. 169:                   If intImplicitDenyObjectACL Then 170:                      For intIndice = 1 To Ubound(arrayImplicitDenyObjectACL) 171:                          ReDim Preserve arrayNewACL(intNewACL) 172:                          Set arrayNewACL(intNewACL) = arrayImplicitDenyObjectACL(intIndice) 173:                          intNewACL = intNewACL + 1 174:                      Next 175:                   End If 176: 177:                   ' Implicit Allow ACE. 178:                   If intImplicitAllowACL Then 179:                      For intIndice = 1 To Ubound(arrayImplicitAllowACL) 180:                          ReDim Preserve arrayNewACL(intNewACL) 181:                          Set arrayNewACL(intNewACL) = arrayImplicitAllowACL(intIndice) 182:                          intNewACL = intNewACL + 1 183:                      Next 184:                   End If 185: 186:                   If intImplicitAllowObjectACL Then 187:                      ' Implicit Allow ACE objects. 188:                      For intIndice = 1 To Ubound(arrayImplicitAllowObjectACL) 189:                          ReDim Preserve arrayNewACL(intNewACL) 190:                          Set arrayNewACL(intNewACL) = arrayImplicitAllowObjectACL(intIndice) 191:                          intNewACL = intNewACL + 1 192:                      Next 193:                   End If 194: 195:                   If intInheritedACL Then 196:                      ' Inherited ACE. 197:                      For intIndice = 1 To Ubound(arrayInheritedACL) 198:                          ReDim Preserve arrayNewACL(intNewACL) 199:                          Set arrayNewACL(intNewACL) = arrayInheritedACL(intIndice) 200:                          intNewACL = intNewACL + 1 201:                      Next 202:                   End If 203: 204:                   objSD.DACL = arrayNewACL 205:                End If 206: 207:' Here we do not have a security descriptor available via this access method. 208:           Case cRegistryViaWMI, _ 209:                cWMINameSpaceViaADSI 210: 211:    End Select 212: 213:    Set ReOrderACE = objSD 214: 215:End Function 

end example

4.12.6.1 Reordering ACEs in the ADSI object model

The overall idea of the logic is to store ACEs in several temporary ACLs (one per category). Once completed, these temporary ACLs are read in the requested order and each ACE is stored in a new ACL. The end result is that this new ACL contains all ACEs in the required order.

At line 50, the ReOrderACE() function extracts the ACL from the DACL. Note that the SACL is not considered, since the ACE order is only important for security accesses. Next, if ACEs are contained in the DACL (line 52), the script creates five new ACL objects: one for the new ordered ACL (line 53) and one new ACL for each category (lines 54 through 58). For each ACE in the ACL, the script enumerates all ACEs and stores each of them in its corresponding ACL category based on its type (lines 60 through 79). Once complete, the new ACL is built from each ACL category created (lines 81 through 104). The end result is a list of ACEs properly ordered. Before returning, the new ACL is stored back to the DACL (line 108).

4.12.6.2 Reordering ACEs in the WMI object model

The ACE reordering under the WMI object model is the same as the ACE ordering in the ADSI object model. Of course, since ACLs under WMI are represented by an array, the code manipulates items in different arrays (one per category). Except for this difference, the logic of Sample 4.50 is exactly the same as Sample 4.49.




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