by Marcin Policht
After looking at the ways of displaying permissions on Windows registry,
it is time to explore methods of changing them. As you realize by now, this
is accomplished by using Access Control Entries associated with each
registry key. Despite some differences, these entries work in a manner very
similar to the one implemented by permissions on the NTFS file system.
Because of this similarity, you might want to refer to another series of my
articles dealing with NTFS permissions (they are also published on the Swynk
web site). They should help you understand the structure of the Access
Control Entries and get familiar with the way these entries can be modified.
Besides setting various propeties of Access Control Entries (such as Acces
Type, Access Flag, or Trustee), ACEs need to be also rearranged in proper
order. You can refer to the Microsoft Knowledge Base article Q269159
for details. The reasons for this additional step are explained briefly in
comments to the Sub ReorderDACL in the script RegPerm.vbs below.
In his latest article, Marcin Policht takes an in-depth look at managing permissions in the Windows Registry using Windows Management Instrumentation (WMI) methods.
The script RegPerm.vbs operates in one of two modes, determined by the
value of the ACTION input parameter. Value of SET, causes the script to
grant or deny the permissions to the registry key (which path is specified
as TARGET input parameter) for a user or group account (set with ACCOUNT
parameter). Value of SHOW, displays the content of access control entries
for an arbitrarily chosen registry key. A separate script offering this
functionality has been presented in the Part 3 of the
series). This script, however, has been modified to allow references to
remote computers. This is done by including a computer name in the TARGET
input parameter. This feature can also be used when modifying permissions
with SET option.
For example, in order to display the permissions on the
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows registry key on the computer
SWYNKPC001, you would run the follwing at the Command Prompt from the folder
in which the RegPerm.vbs resides:
cscript /nologo RegPerm.vbs ACTION=SHOW
TARGET="SWYNKPC001HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows"
If you omit computer name entry in the target registry path, the script
will set the permissions on the local system:
cscript /nologo RegPerm.vbs ACTION=SHOW
TARGET="HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows"
Setting permissions requires providing two additional parameters: ACCOUNT
and PERM. Domain accounts need to be specified in the format
DOMAINAccountName, e.g. SWYNKMPolicht (for MPolicht account in the SWYNK
domain). If the account is local, you can use the format
COMPUTERNAMEAccountName or simply AccountName. PERM parameter can take one
of the following values:
- FULL
- WRITE
- READ
- NOACCESS
- “” (empty string)
FULL grants the account you specified with ACCOUNT parameter full control
over the key. WRITE allows writing to the registry key by setting three
individual permissions (KEY_SET_VALUE, KEY_CREATE_SUB_KEY, and
READ_CONTROL). NOACCESS denies Full Control to the key, which effectively
prevents any type of access. Finally, if PERM is set to an empty string ,
the account is removed from the list of Access Control Entries. Note, that
removing the account from the list of ACEs is different from setting
NOACCESS permissions. The latter will always prevent access for a given
account, the former might still allow access if a group that account is a
member of has some type of permissions granted.
The permissions set with the script will overwrite any of the existing
permissions, but only for the account you specify. They will also be
granted only to the key itself (and all of its values), but will not
propagate to any of the subkeys. However, you can use the INH input
parameter (which can be set to values YES or NO), which determines the
permissions inheritance by all subkeys created afterwards. Setting INH to
YES, will cause permissions set by the script on the top level key to be
inherited by any new subkeys. Correspondingly, setting INH to NO (default)
will ensure that permissions on any new subkeys will not contain the ACE set
by the script. Note that the INH parameter only affects the entry for the
single user account that you specified when running the script.
Here are a few examples of using the SET option:
cscript /nologo RegPerm.vbs ACTION=SET
TARGET="SWYNKPC001HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows"
ACCOUNT=SWYNKMPolicht PERM=FULL INH=NO
will grant the Full Control permissions for the
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows key on the SWYNKPC001 computer
to the SWYNKMPolicht account and prevent inheritance.
cscript /nologo RegPerm.vbs ACTION=SET
TARGET="SWYNKPC001HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows"
ACCOUNT=SWYNKMPolicht PERM=READ
will change these permissions to Read (and maintain inheritance settings,
since NO is the default)
cscript /nologo RegPerm.vbs ACTION=SET
TARGET="SWYNKPC001HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows"
ACCOUNT=SWYNKMPolicht PERM=
will remove entry for SWYNKMPolicht account from the list of Access Control
Entries.
Remember that the script requires ADsSecurity.dll to be present and
registered on the system from which the script is running. As mentioned
before, this DLL is included in the ADSI 2.5 Software Development Kit (SDK)
downloadable from the Microsoft Web site.
'//////////////////////////////////////////////////////////////////////////
'/// Name: RegPerm.vbs
'/// Version: 1.0
'/// Date: 09/01/02
'/// Purpose: displaying and setting permissions on the registry keys
'/// OS: Windows 2000, XP
'/// Reqs: ADsSecurity.dll (registered)
'/// Syntax: cscript /nologo RegPerm.vbs ACTION=SET TARGET=Registry_Key _
'/// ACCOUNT=DomainAccount PERM=Read|Change|Full|NoAccess INH=YES|NO"
'/// where ACTION is set to SHOW or SET (to display or set permissions)"
'/// TARGET is full path to registry key (computer name is optional)
'/// e.g. "ComputerHKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows"
'/// if computer name is omitted, local system is used
'/// ACCOUNT is user or group in DOMAINAccountName format
'/// PERM specifies type of permissions to be set
'/// INH determines permission inheritance (Yes or No)
'//////////////////////////////////////////////////////////////////////////
Option Explicit
'On Error Resume Next
'////////////////////////////////////////////////////
'/// Constant Declarations
'////////////////////////////////////////////////////
'/// Access Control Entry Inheritance Flags
'/// Allowed values for the IADsAccessControlEntry::AceFlags property.
const ADS_ACEFLAG_UNKNOWN = &h1
'/// child objects will inherit ACE of current object
const ADS_ACEFLAG_INHERIT_ACE = &h2
'/// prevents ACE inherited by the object from further propagation
const ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE = &h4
'/// indicates ACE used only for inheritance (it does not affect permissions
on object itself)
const ADS_ACEFLAG_INHERIT_ONLY_ACE = &h8
'/// indicates that ACE was inherited
const ADS_ACEFLAG_INHERITED_ACE = &h10
'/// indicates that inherit flags are valid (provides confirmation of valid
settings)
const ADS_ACEFLAG_VALID_INHERIT_FLAGS = &h1f
'/// for auditing success in system audit ACE
const ADS_ACEFLAG_SUCCESSFUL_ACCESS = &h40
'/// for auditing failure in system audit ACE
const ADS_ACEFLAG_FAILED_ACCESS = &h80
'//////////////////////////////////////////////////
'/// Access Control Entry Type Values
'/// Allowed values for the IADsAccessContronEntry::AceType property.
const ADS_ACETYPE_ACCESS_ALLOWED = 0
const ADS_ACETYPE_ACCESS_DENIED = &h1
const ADS_ACETYPE_SYSTEM_AUDIT = &h2
const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &h5
const ADS_ACETYPE_ACCESS_DENIED_OBJECT = &h6
const ADS_ACETYPE_SYSTEM_AUDIT_OBJECT = &h7
'//////////////////////////////////////////////////
'/// Registry Permission Type Values
Const KEY_QUERY_VALUE = &H0001
Const KEY_SET_VALUE = &H0002
Const KEY_CREATE_SUB_KEY = &H0004
Const KEY_ENUMERATE_SUB_KEYS = &H0008
Const KEY_NOTIFY = &H0010
Const KEY_CREATE_LINK = &H0020
Const DELETE = &H00010000
Const READ_CONTROL = &H00020000
Const WRITE_DAC = &H00040000
Const WRITE_OWNER = &H00080000
Dim KEY_READ 'access mask designating read access to registry key
Dim KEY_WRITE 'access mask designating write access to registry key
Dim KEY_ALL_ACCESS 'access mask designating full access to registry key
Dim iOffset 'used for display only (left justifying displayed values)
Dim sAction 'type of action to perform (show or set)
Dim sPermission 'permission type (read, change, full, or no access)
Dim sAccount 'user or group account for which permissions are set
Dim sTarget 'string representing path to target registry key
Dim sInh 'value representing inheritance behavior (1 yes, 0 no)
Dim oADSSecurity 'object representing ADsSecurity class
Dim oTargetSD 'object representing security descriptor of registry key
Dim oDACL 'object representing Discretionary Access Control List
'//////////////////////////////////////////////////
'/// Set variables
'/// KEY_READ is a combination of KEY_QUERY_VALUE,
' KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and READ_CONTROL access.
KEY_READ = KEY_QUERY_VALUE + KEY_ENUMERATE_SUB_KEYS + KEY_NOTIFY +
READ_CONTROL
'/// KEY_WRITE is a combination of KEY_SET_VALUE and KEY_CREATE_SUB_KEY
access.
KEY_WRITE = KEY_SET_VALUE + KEY_CREATE_SUB_KEY + READ_CONTROL
'/// KEY_FULL_ACCESS is a combination of KEY_QUERY_VALUE, KEY_SET_VALUE,
' KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_LINK,
' DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access.
KEY_ALL_ACCESS = KEY_QUERY_VALUE + KEY_SET_VALUE + KEY_CREATE_SUB_KEY + _
KEY_ENUMERATE_SUB_KEYS + KEY_NOTIFY + KEY_CREATE_LINK + _
DELETE + READ_CONTROL + WRITE_DAC + WRITE_OWNER
iOffset = 20
'//////////////////////////////////////////////////
'/// Retrieve script arguments
Call GetArguments(Wscript.Arguments, sAction, sTarget, sAccount,
sPermission, sInh)
Set oADSSecurity = CreateObject("ADsSecurity")
Set oTargetSD = oADsSecurity.GetSecurityDescriptor("RGY://" & sTarget)
Set oDACL = oTargetSD.DiscretionaryACL
Select Case UCase(sAction)
Case "SHOW"
Call DisplayACLs()
Case "SET"
Call SetACLs(sAccount, sPermission, sInh)
Case Else
Call DisplayUsage("ERROR: Incorrect ACTION type")
End Select
Set oDACL = Nothing
Set oTargetSD = Nothing
Set oADsSecurity = Nothing
Wscript.Quit
'///////////////////////////////////////////////////////////////////
'/// Name: GetArguments
'/// Purpose: Reading command line arguments
'/// Input: oArgs WScript.Arguments collection
'/// Output: sAction Action type (SET or SHOW)
'/// sTarget Registry key
'/// sAccount Account to set permissions for
'/// sPermission Type of permissions to set
'/// sInh Permission inheritance (1 yes, 0 no)
'///////////////////////////////////////////////////////////////////
Sub GetArguments(oArgs, sAction, sTarget, sAccount, sPermission, sInh)
Dim iCount
For iCount=0 To oArgs.Count - 1
Select Case UCase(Split(WScript.Arguments(iCount), "=")(0))
Case "ACTION" sAction = Split(WScript.Arguments(iCount), "=")(1)
Case "TARGET" sTarget = Split(WScript.Arguments(iCount), "=")(1)
Case "ACCOUNT" sAccount = Split(WScript.Arguments(iCount), "=")(1)
Case "PERM" sPermission = Split(WScript.Arguments(iCount), "=")(1)
Case "INH" sInh = Split(WScript.Arguments(iCount), "=")(1)
End Select
Next
If sAction = "" or sTarget = "" or (sAction = "SET" and (sTarget = "" or
sAccount = "")) Then
Call DisplayUsage("ERROR: Missing argument(s)")
WScript.Quit
End If
end sub
'///////////////////////////////////////////////////////////////////
'/// Name: DisplayUsage
'/// Purpose: Displaying usage of the script from the command line
'/// Input: sHeader Header for Message Box
'///////////////////////////////////////////////////////////////////
sub DisplayUsage(sHeader)
Dim sMsg
sMsg = "To display permissions on a registry key, run:"
sMsg = sMsg & VbCrLf & _
"cscript //nologo RegPerms.vbs ACTION=SHOW TARGET=Registry_Key"
sMsg = sMsg & VbCrLf & vbCrLf & "To set permissions on a registry key run:"
sMsg = sMsg & VbCrLf & _
"cscript //nologo RegPerms.vbs ACTION=SET TARGET=Registry_Key " & _
"ACCOUNT=DomainAccount PERM=Read|Change|Full|NoAccess INH=YES|NO"
sMsg = sMsg & VbCrLf & vbCrLf & "Where:"
sMsg = sMsg & VbCrLf & String(7," ") & "ACTION is set to SHOW or SET (to
display or set permissions, respectively)"
sMsg = sMsg & VbCrLf & String(7," ") & "TARGET is full path to the registry
key (computer name is optional)"
sMsg = sMsg & VbCrLf & String(7," ") & "e.g. " &
"""ComputerHKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows"""
sMsg = sMsg & VbCrLf & String(7," ") & "ACCOUNT is user or group account in
the DOMAINAccountName format"
sMsg = sMsg & VbCrLf & String(7," ") & "PERM specifies type of permissions
to be set"
sMsg = sMsg & VbCrLf & String(7," ") & "INH determines permission
inheritance (Yes or No)"
Call MsgBox(sMsg, vbOKOnly, sHeader)
end sub
'///////////////////////////////////////////////////////////////////
'/// Name: SetACLs
'/// Purpose: Setting Access Control List entry
'/// Input: sAccount Account to set permissions for
'/// sPermission Type of permissions to set
'/// sInh Permission inheritance (yes or no)
'///////////////////////////////////////////////////////////////////
Sub SetACLs(sAccount, sPermission, sInh)
Dim oACE
For Each oACE in oDACL
If UCase(oACE.Trustee) = UCase(sAccount) Then
oDACL.RemoveACE oACE
End if
Next
oTargetSD.DiscretionaryACL = oDACL
oADsSecurity.SetSecurityDescriptor oTargetSD
Set oACE = CreateObject("AccessControlEntry")
oACE.Trustee = sAccount
Select Case UCase(sPermission)
Case "FULL"
oACE.AccessMask = KEY_ALL_ACCESS
oACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED
Case "CHANGE"
oACE.AccessMask = KEY_WRITE
oACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED
Case "READ"
oACE.AccessMask = KEY_READ
oACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED
Case "NOACCESS"
oACE.AccessMask = KEY_ALL_ACCESS
oACE.AceType = ADS_ACETYPE_ACCESS_DENIED
Case ""
Exit Sub
Case Else
DisplayUsage("ERROR: Incorrect Permission Type")
End Select
If UCase(sInh) = "YES" Then
oACE.AceFlags = ADS_ACEFLAG_INHERIT_ACE
Else
oACE.AceFlags = ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE
End If
oDACL.AddAce oACE
Call ReorderDACL(oDACL)
oTargetSD.DiscretionaryACL = oDACL
oADsSecurity.SetSecurityDescriptor oTargetSD
End Sub
'///////////////////////////////////////////////////////////////////
'/// Name: ReorderDACL
'/// Purpose: reordering the ACLs (per Q269159)
'/// ACEs need to be ordered, since AddAce method does not take care of
it.
'/// For Windows 2000 and later, ACEs should be arranged into two main
groups
'/// - non-inherited
'/// - inherited.
'/// Non-inherited ACEs should be listed first, followed by the inherited
ones.
'/// Within each group, ACEs are arranged in the following fashion:
'/// - access-denied ACEs that apply to the object itself
'/// - access-denied ACEs that apply to subobjects of the object
'/// - access-allowed ACEs that apply to the object itself
'/// - access-allowed ACEs that apply to subobjects of the object
'/// Since the script does not affect inherited ACEs (but instead, it sets
'/// permission directly on target object), they do not have to be
rearranged.
'/// Only non-inherited ACEs are rearranged.
'/// Input: oOrgDACL object representing discretionary access list for
registry key
'///////////////////////////////////////////////////////////////////
Sub ReorderDACL(oDACL)
Dim oNewDACL 'object used to temporarily store DACL (during ordering)
Dim oInheritedDACL 'object representing list of all Inherited ACEs
Dim oDenyDACL 'object representing list of non-Inherited Deny ACEs
Dim oDenyObjDACL 'object representing list of non-Inherited Deny Object
ACEs
Dim oAllowDACL 'object representing list of non-Inherited Allow ACEs
Dim oAllowObjDACL 'object representing list of non-Inherited Allow Object
ACEs
Dim oACE 'object representing ACE (used for enumeration)
'//////////////////////////////////////////////////
'/// Create Access Control List objects
Set oNewDACL = CreateObject("AccessControlList")
Set oInheritedDACL = CreateObject("AccessControlList")
Set oAllowDACL = CreateObject("AccessControlList")
Set oDenyDACL = CreateObject("AccessControlList")
Set oDenyObjDACL = CreateObject("AccessControlList")
Set oAllowObjDACL = CreateObject("AccessControlList")
'//////////////////////////////////////////////////
'/// Add individual ACEs into each of the lists
'/// based on the ACE Flags and ACE Type values
For Each oACE In oDACL
If ((oACE.AceFlags AND ADS_ACEFLAG_INHERITED_ACE) =
ADS_ACEFLAG_INHERITED_ACE) Then
'//////////////////////////////////////////////////
'/// as explained, no sorting is needed for Inherited ACEs, they are simply
'/// added to the list and retrieved at the end of the sub in the same
order
oInheritedDACL.AddAce oACE
Else
'//////////////////////////////////////////////////
'/// non-Inherited ACEs need to be placed in their respective list to be
re-ordered
Select Case oACE.AceType
Case ADS_ACETYPE_ACCESS_ALLOWED
oAllowDACL.AddAce oACE
Case ADS_ACETYPE_ACCESS_DENIED
oDenyDACL.AddAce oACE
Case ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
oAllowObjDACL.AddAce oACE
Case ADS_ACETYPE_ACCESS_DENIED_OBJECT
oDenyObjDACL.AddAce oACE
End Select
End If
Next
'//////////////////////////////////////////////////
'/// Recreate the Access Control List following the appropriate order
'/// - non-Inherited Deny ACEs
'/// - non-Inherited Allow ACEs
'/// - Inherited ACEs
For Each oACE In oDenyDACL
oNewDACL.AddAce oACE
Next
For Each oACE In oDenyObjDACL
oNewDACL.AddAce oACE
Next
For Each oACE In oAllowDACL
oNewDACL.AddAce oACE
Next
For Each oACE In oAllowObjDACL
oNewDACL.AddAce oACE
Next
For Each oACE In oInheritedDACL
oNewDACL.AddAce oACE
Next
Set oInheritedDACL = Nothing
Set oDenyDACL = Nothing
Set oAllowDACL = Nothing
Set oDenyObjDACL = Nothing
Set oAllowObjDACL = Nothing
'//////////////////////////////////////////////////
'/// Set appropriate DACL revision level
oNewDACL.AclRevision = oDACL.AclRevision
'//////////////////////////////////////////////////
'/// Reset the original DACL
Set oDACL = Nothing
Set oDACL = oNewDACL
end Sub
'///////////////////////////////////////////////////////////////////
'/// Name: DisplayACLs
'/// Purpose: Displaying Access Control List entries
'///////////////////////////////////////////////////////////////////
Sub DisplayACLs()
Dim oACE 'object representing individual ACE
Dim sMsg, sAccessMask 'strings containing message to be displayed
Dim hAccessMask 'number representing Access Mask value
WScript.Echo "Permissions on " & sTarget
For Each oACE in oDACL
sMsg = vbCrLf & "Trustee:" & String(iOffset - Len("Trustee:"), Chr(32)) &
_
oACE.Trustee & vbCrLf
sMsg = sMsg & "ACE Type:" & String(iOffset - Len("ACE Type:"), Chr(32))
Select Case oACE.AceType
Case ADS_ACETYPE_ACCESS_ALLOWED
'Implicit Allow ACE
sMsg = sMsg & "ACCESS_ALLOWED"
Case ADS_ACETYPE_ACCESS_DENIED
'Implicit Deny ACE
sMsg = sMsg & "ACCESS_DENIED"
Case ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
'Object Allowed ACE
sMsg = sMsg & "ACCESS_ALLOWED_OBJECT"
Case ADS_ACETYPE_ACCESS_DENIED_OBJECT
'Object Deny ACE
sMsg = sMsg & "ACCESS_DENIED_OBJECT"
End Select
Wscript.Echo sMsg
sAccessMask = ""
hAccessMask = 0
If (oACE.AccessMask AND KEY_QUERY_VALUE) Then
sAccessMask = String(iOffset, Chr(32)) & "KEY_QUERY_VALUE" & vbCrLf
hAccessMask = hAccessMask + KEY_QUERY_VALUE
End If
If (oACE.AccessMask AND KEY_SET_VALUE) Then
sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "KEY_SET_VALUE" &
vbCrLf
hAccessMask = hAccessMask + KEY_SET_VALUE
End If
If (oACE.AccessMask AND KEY_CREATE_SUB_KEY) Then
sAccessMask = sAccessMask & String(iOffset, Chr(32)) &
"KEY_CREATE_SUB_KEY" & vbCrLf
hAccessMask = hAccessMask + KEY_CREATE_SUB_KEY
End If
If (oACE.AccessMask AND KEY_ENUMERATE_SUB_KEYS) Then
sAccessMask = sAccessMask & String(iOffset, Chr(32)) &
"KEY_ENUMERATE_SUB_KEYS" & vbCrLf
hAccessMask = hAccessMask + KEY_ENUMERATE_SUB_KEYS
End If
If (oACE.AccessMask AND KEY_NOTIFY) Then
sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_WRITE_EA" &
vbCrLf
hAccessMask = hAccessMask + KEY_NOTIFY
End If
If (oACE.AccessMask AND KEY_CREATE_LINK) Then
sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "KEY_CREATE_LINK"
& vbCrLf
hAccessMask = hAccessMask + KEY_CREATE_LINK
End If
If (oACE.AccessMask AND DELETE) Then
sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "DELETE" & vbCrLf
hAccessMask = hAccessMask + DELETE
End If
If (oACE.AccessMask AND READ_CONTROL) Then
sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "READ_CONTROL" &
vbCrLf
hAccessMask = hAccessMask + READ_CONTROL
End If
If (oACE.AccessMask AND WRITE_DAC) Then
sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "WRITE_DAC" &
vbCrLf
hAccessMask = hAccessMask + WRITE_DAC
End If
If (oACE.AccessMask AND WRITE_OWNER) Then
sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "WRITE_OWNER" &
vbCrLf
hAccessMask = hAccessMask + WRITE_OWNER
End If
sMsg = "ACE Permissions:" & String(iOffset - Len("ACE Permissions:"),
Chr(32))
Select Case hAccessMask
Case KEY_ALL_ACCESS Wscript.Echo sMsg & "FULL CONTROL"
Case KEY_WRITE Wscript.Echo sMsg & "WRITE"
Case KEY_READ Wscript.Echo sMsg & "READ"
Case Else WScript.Echo sMsg & oACE.AccessMask
WScript.Echo sAccessMask
End Select
sMsg = "ACE Flags:" & String(iOffset - Len("ACE Flags:"), Chr(32))
If (oACE.AceFlags AND ADS_ACEFLAG_INHERIT_ACE) Then
WScript.Echo sMsg & "ADS_ACEFLAG_INHERIT_ACE"
End If
If (oACE.AceFlags AND ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE) Then
WScript.Echo sMsg & "ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE"
End If
If (oACE.AceFlags AND ADS_ACEFLAG_INHERIT_ONLY_ACE) Then
WScript.Echo sMsg & "ADS_ACEFLAG_INHERIT_ONLY_ACE"
End If
If (oACE.AceFlags AND ADS_ACEFLAG_INHERITED_ACE) Then
WScript.Echo sMsg & "ADS_ACEFLAG_INHERITED_ACE"
End If
If (oACE.AceFlags AND ADS_ACEFLAG_VALID_INHERIT_FLAGS) Then
WScript.Echo sMsg & "ADS_ACEFLAG_VALID_INHERIT_FLAGS"
End If
If (oACE.AceFlags AND ADS_ACEFLAG_SUCCESSFUL_ACCESS) Then
WScript.Echo sMsg & "ADS_ACEFLAG_SUCCESSFUL_ACCESS"
End If
If (oACE.AceFlags AND ADS_ACEFLAG_FAILED_ACCESS) Then
WScript.Echo sMsg & "ADS_ACEFLAG_FAILED_ACCESS"
End If
If (oACE.AceFlags AND ADS_ACEFLAG_UNKNOWN) Then
WScript.Echo sMsg & "ADS_ACEFLAG_UNKNOWN"
End If
Next
End Sub