Scripting NTFS Permissions with ADSI (Part 3)

By ServerWatch Staff (Send Email)
Posted May 21, 2002


by Marcin Policht


In his latest article in a series discussing a scripting approach to modifying Security Descriptors, Marcin Policht discusses how to make modifications to Security Descriptors that control permissions to files and folders on NTFS-based partitions.

This is the third article in the series discussing a scripting approach to modifying Security Descriptors. In the first two articles, I introduced the concept of the Security Descriptor and described its components. Next, I described a way to extract information about it through ADSI-based scripting. In this article, you will find out how to make modifications to Security Descriptors that control permissions to files and folders on NTFS-based partitions. As before, keep in mind that in order for the script to work, you will need to obtain ADsSecurity.DLL file (which is included in the ADSI Software Development Kit, freely downloadable from the Microsoft Web Site), copy it to the computer where the script will be run, and register it using REGSVR32.EXE (refer to the first article of the series for details).

After you have registered ADsSecurity.DLL, copy the script to a text file and and save it as ACLs.vbs. This version combines the capability included in the script presented in the previous article, which allowed displaying permissions with the ability to set permissions.

After saving the script, you can execute it by typing appropriate command at the Command Prompt:

To display the Security Descriptor (Trustees, ACE Flags, and Access Control Entries) for a file or folder, you would use the following syntax:

cscript //nologo ACLs.wsf ACTION=SHOW TARGET=[File|Folder] [ACCOUNT=Domain\Account]

where

  • SHOW is used to indicate type of action (displaying Access Control Entries)
  • File|Folder is a full path to the file or folder
  • Domain\Account is an optional argument that allows you to limit the listing to a specific user or group account (in the format domain\account)
To set ACE of a file or folder for a particular user or group, you would type the following:

cscript //nologo ACLs.wsf ACTION=SET TARGET=[File|Folder] ACCOUNT=Domain\Account PERM=[Read|Change|Full|NoAccess]

where
  • SET is used to indicate the type of action (setting Access Control Entry)
  • File|Folder is a full path to the file or folder on which permissions will be set
  • Domain\Account is a mandatory argument and specifies the user or group account for which permissions to file/folder will be set
  • Read|Change|Full|NoAccess is the type of permissions set on the target file or folder (can be any one of these four)

You can find out the proper syntax simply by double-clicking on the file. The same message box is displayed if you happen to provide the wrong number of arguments. Here are some examples of a proper use of the script:

To display the full content of security descriptor for a file c:\boot.ini, you would run:
cscript //nologo ACLs.wsf ACTION=SHOW TARGET=c:\boot.ini

If you wanted to limit the display of ACEs to a single trustee only (e.g. MPolicht account from the SWYNK domain), you would execute:
cscript //nologo ACLs.wsf ACTION=SHOW TARGET=c:\boot.ini ACCOUNT=SWYNK\MPolicht

And the following command would grant FULL CONTROL permissions on c:\boot.ini to a trustee (SWYNK\MPolicht in this case):
cscript //nologo ACLs.wsf ACTION=SET TARGET=c:\boot.ini ACCOUNT=SWYNK\MPolicht PERM=FULL

The target parameter for both SHOW and SET actions can be either a file or folder. When used with a file, SHOW (and SET) will display (and modify) permissions on the target file. When applied to folders, SHOW will display permissions on the folder only; SET however, will modify permissions on the folder and all of its content (including subfolders and their content, recursively). Note that the permissions will be replaced by the one you provide on the command line (i.e. Read, Change, Full, or No Access) but only for the account you specify with the ACCOUNT parameter. Permissions for any other user or group accounts will remain unaffected.

It is also important to realize that, when performing SET action on a folder, permissions are assigned explicitly (not through inheritance). In other words, the script will traverse each file and subfolder within the target folder and assign permissions directly to each. This is different from the default Windows 2000 behavior, which assigns explicit permissions only to the parent folder (while effective permissions on its content are determined based on inheritance settings).

Any new files or subfolders created in the target folder, do, however, properly inherit permissions from their parent.

The script consists of the following subroutines:

  • GetArguments - Reading command line arguments
  • DisplayUsage - Displaying MessageBox listing proper syntax for script execution
  • DisplayACLs - Displaying a list of Access Control Entries for the target file or folder (explained in the previous article)
  • RecurseACLs - Recursing through the folder hierarchy in order to allow changing permissions for all child files and folders
  • SetACLs - Setting appropriate access control entry on a file or folder for the account specified as the input argument (this is the critical part of the script, which actually modifies the ACE)
  • ReorderDACL - Rearranging the sequence of Access Control Entries in the Access Control List. This step is necessary, since access control entries are supposed to follow a certain order -- those denying access should always precede those that allow it. Unfortunately, the process used to set ACEs (in SetACLs sub) does not maintain this ordering, hence the additional cleanup.
    • 
      Option Explicit
      
      '**************************************************
      '*** Constant Declarations
      
      '**************************************************
      '*** Access Control Entry Inheritance Flags
      '*** Possible 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
      '*** Possible 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
      
      '**************************************************
      '*** Access Control Entry Permission Type Values
      '*** Possible values for the IADsAccessControlEntry::AccessMask property.  
      
      '*** permission to read data from file or list contents of directory
      '*** corresponds to List Folder / Read Data permissions in Windows UI
      const FILE_READ_DATA 				= &h1		'bit number 0
      const FILE_LIST_DIRECTORY 			= &h1		'bit number 0
      
      '*** permission to write data to file or create file in directory
      '*** corresponds to Create Files / Write Data permissions in Windows UI
      const FILE_WRITE_DATA 				= &h2		'bit number 1
      const FILE_ADD_FILE 				= &h2		'bit number 1
      
      '*** permission to append data to file or to create subdirectory
      '*** corresponds to Create Folders / Append Data permissions in Windows UI
      const FILE_APPEND_DATA				= &h4		'bit number 2
      const FILE_ADD_SUBDIRECTORY 			= &h4		'bit number 2
      
      '*** permission to read extended attributes
      '*** corresponds to Read Extended Attributes permissions in Windows UI
      const FILE_READ_EA 				= &h8		'bit number 3
      
      '*** permission to write extended attributes
      '*** corresponds to Write Extended Attributes permissions in Windows UI
      const FILE_WRITE_EA				= &h10		'bit number 4
      
      '*** permission to execute file or traverse directory
      '*** corresponds to Traverse Folder / Execute File permissions in Windows UI
      const FILE_EXECUTE 				= &h20		'bit number 5
      const FILE_TRAVERSE 				= &h20		'bit number 5
      
      '*** permission to delete directory and all files it contains
      '*** corresponds to Delete Subfolders and Files permissions in Windows UI
      const FILE_DELETE_CHILD 			= &h40		'bit number 6
      
      '*** permission to read file or folder attributes
      '*** corresponds to Read Attributes permissions in Windows UI
      const FILE_READ_ATTRIBUTES 			= &h80		'bit number 7
      
      '*** permission to change file or folder attributes
      '*** corresponds to Write Attributes permissions in Windows UI
      const FILE_WRITE_ATTRIBUTES			= &h100		'bit number 8
      
      '*** permission to delete file or folder
      '*** corresponds to Delete permissions in Windows UI
      const DELETE 					= &h10000	'bit number 16
      
      '*** permission to read security descriptor
      '*** corresponds to Read Permissions permissions in Windows UI
      const READ_CONTROL				= &h20000	'bit number 17
      
      '*** permission to change discretionary ACL
      '*** corresponds to Change Permissions permissions in Windows UI
      const WRITE_DAC 				= &h40000	'bit number 18
      
      '*** permission to assign owner
      '*** corresponds to Take Ownership permissions in Windows UI
      const WRITE_OWNER				= &h80000	'bit number 19
      
      '*** permission to synchronize
      '*** bit indicating permission to perform synchronize operation, used sometimes during file access
      '*** this permission is automaticaly granted with read and write access and revoked when read or 
      '*** write access is denied. It is not displayed in the list of permissions in Windows UI
      const SYNCHRONIZE 				= &h100000	'bit number 20
      
      const ADS_RIGHT_GENERIC_ALL            		= &h10000000	'bit number 28
      const ADS_RIGHT_GENERIC_EXECUTE        		= &h20000000	'bit number 29
      const ADS_RIGHT_GENERIC_WRITE          		= &h40000000	'bit number 30
      const ADS_RIGHT_GENERIC_READ           		= &h80000000	'bit number 31
      
      '**************************************************
      '*** Variable Declarations
      
      Dim adsFILE_FULL	'value representing sum of access mask corresponding to full file access
      Dim adsFOLDER_FULL	'value representing sum of access mask corresponding to full folder access
      Dim adsFILE_CHANGE	'value representing sum of access mask corresponding to change file access
      Dim adsFOLDER_CHANGE	'value representing sum of access mask corresponding to change folder access
      Dim adsFILE_READ	'value representing sum of access mask corresponding to read file access
      Dim adsFOLDER_READ	'value representing sum of access mask corresponding to read folder access
      Dim adsFILE_NOACCESS	'value representing sum of access mask corresponding to denied full file access
      Dim adsFOLDER_NOACCESS	'value representing sum of access mask corresponding to denied full folder access
      
      adsFILE_FULL		= FILE_READ_DATA Or FILE_WRITE_DATA Or FILE_APPEND_DATA Or _
      			FILE_READ_EA Or FILE_WRITE_EA Or FILE_EXECUTE Or FILE_DELETE_CHILD Or _
      			FILE_READ_ATTRIBUTES Or FILE_WRITE_ATTRIBUTES Or DELETE Or _
      			READ_CONTROL Or WRITE_DAC Or WRITE_OWNER Or SYNCHRONIZE
      adsFOLDER_FULL 		= FILE_LIST_DIRECTORY Or FILE_ADD_FILE Or FILE_ADD_SUBDIRECTORY Or _
      			FILE_READ_EA Or FILE_WRITE_EA Or FILE_TRAVERSE Or FILE_DELETE_CHILD Or _
      			FILE_READ_ATTRIBUTES Or FILE_WRITE_ATTRIBUTES Or DELETE Or _
      			READ_CONTROL Or WRITE_DAC Or WRITE_OWNER Or SYNCHRONIZE
      adsFILE_CHANGE 		= FILE_READ_DATA Or FILE_WRITE_DATA Or FILE_APPEND_DATA Or _
      			FILE_READ_EA Or FILE_WRITE_EA Or FILE_EXECUTE Or _
      			FILE_READ_ATTRIBUTES Or FILE_WRITE_ATTRIBUTES Or DELETE Or _
      			READ_CONTROL Or SYNCHRONIZE
      adsFOLDER_CHANGE	= FILE_LIST_DIRECTORY Or FILE_ADD_FILE Or FILE_ADD_SUBDIRECTORY Or _
      			FILE_READ_EA Or FILE_WRITE_EA Or FILE_TRAVERSE Or _
      			FILE_READ_ATTRIBUTES Or FILE_WRITE_ATTRIBUTES Or DELETE Or _
      			READ_CONTROL Or SYNCHRONIZE
      adsFILE_READ 		= FILE_READ_DATA Or FILE_READ_EA Or FILE_EXECUTE Or _
      			FILE_READ_ATTRIBUTES Or READ_CONTROL Or SYNCHRONIZE
      adsFOLDER_READ		= FILE_LIST_DIRECTORY Or FILE_READ_EA Or FILE_TRAVERSE Or _
      			FILE_READ_ATTRIBUTES Or READ_CONTROL Or SYNCHRONIZE
      adsFILE_NOACCESS 	= FILE_READ_DATA Or FILE_WRITE_DATA Or FILE_APPEND_DATA Or _
      			FILE_READ_EA Or FILE_WRITE_EA Or FILE_EXECUTE Or FILE_DELETE_CHILD Or _
      			FILE_READ_ATTRIBUTES Or FILE_WRITE_ATTRIBUTES Or DELETE Or _
      			READ_CONTROL Or WRITE_DAC Or WRITE_OWNER
      adsFOLDER_NOACCESS 	= FILE_LIST_DIRECTORY Or FILE_ADD_FILE Or FILE_ADD_SUBDIRECTORY Or _
      			FILE_READ_EA Or FILE_WRITE_EA Or FILE_TRAVERSE Or FILE_DELETE_CHILD Or _
      			FILE_READ_ATTRIBUTES Or FILE_WRITE_ATTRIBUTES Or DELETE Or _
      			READ_CONTROL Or WRITE_DAC Or WRITE_OWNER
      
      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 shown/set
      Dim sTarget		'target file or folder path
      Dim iTarget		'integer indicating type of target 0 - file, 1 - folder
      Dim iOffset		'value used for display only (left justifying displayed values)
      
      Dim oADSSecurity	'object representing ADsSecurity class
      Dim oFSO		'object representing Scripting.FileSystemObject ProgID
      
      '**************************************************
      '*** Retrieve script arguments
      
      Call GetArguments(Wscript.Arguments, sAction, sTarget, sAccount, sPermission)
      
      '**************************************************
      '*** Set variables
      
      iOffset 		= 20
      Set oFSO 		= CreateObject("Scripting.FileSystemObject")
      Set oADSSecurity 	= CreateObject("ADsSecurity")
      
      If oFSO.FileExists(sTarget) Then 
      	iTarget = 0
      ElseIf oFSO.FolderExists(sTarget) Then
      	iTarget = 1
      Else
      	Call MsgBox("Target File or Folder does not exist", vbOKOnly, "Incorrect argument")
      	WScript.Quit
      End If
      
      Select Case UCase(sAction)
      	Case "SHOW"	
      			Call DisplayACLs(sTarget, sAccount)
      	Case "SET"	
      			Call RecurseACLs(sTarget, sAccount, sPermission)
      	Case Else
      			Call DisplayUsage("ERROR: Incorrect ACTION type")			
      End Select
      
      Wscript.Quit
      
      '**************************************************
      '*** Subroutine reading command line arguments
      '
      Sub GetArguments(oArgs, sAction, sTarget, sAccount, sPermission)
      
      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)
      	End Select
      Next
      
      If sAction = "" or sTarget = "" or (sAction = "SET" and (sTarget = "" or sAccount = "" or sPermission = "")) Then
      	Call DisplayUsage("ERROR: Missing argument(s)")
      	WScript.Quit
      End If
      
      end sub	
      
      
      '**************************************************
      '*** Subroutine displaying usage of the script from the command line
      '
      sub DisplayUsage(sHeader)
      
      Dim sMsg
      
      	sMsg = "To display permissions on file/folder (ACCOUNT parameter is optional) run:"
      	sMsg = sMsg & VbCrLf & _
      		"cscript //nologo ACLs.vbs ACTION=SHOW TARGET=[File|Folder] [ACCOUNT=Domain\Account]"
      	sMsg = sMsg & VbCrLf & vbCrLf & "To set permissions on file/folder (ACCOUNT parameter is mandatory) run:"
      	sMsg = sMsg & VbCrLf & _
      		"cscript //nologo ACLs.vbs ACTION=SET TARGET=[File|Folder] 
      		ACCOUNT=Domain\Account PERM=[Read|Change|Full|NoAccess]"
      	sMsg = sMsg & VbCrLf & vbCrLf & "Where:"
      	sMsg = sMsg & VbCrLf & String(7," ") & "ACTION is set to SHOW to display permissions"
      	sMsg = sMsg & VbCrLf & String(7," ") & "TARGET is full path to the file or folder"
      	sMsg = sMsg & VbCrLf & String(7," ") & "ACCOUNT is user or group account in the DOMAIN\AccountName format"
      	sMsg = sMsg & VbCrLf & String(7," ") & "PERM specifies type of permissions to be set"
      
      	Call MsgBox(sMsg, vbOKOnly, sHeader)
      
      end sub
      
      '**************************************************
      '*** Subroutine displaying list of Trustees, AcL Types, and ACL Masks
      '
      Sub DisplayACLs(sTarget, sAccount)
      
      Dim oACE		'object representing an Access Control Entry
      Dim sMsg, sAccessMask	'strings containing message to be displayed
      Dim hAccessMask		'number representing Access Mask value
      Dim oTargetSD		'object representing security descriptor of target file or folder
      Dim oDACL		'object representing Discretionary Access Control List
      
      set oTargetSD = oADsSecurity.GetSecurityDescriptor("FILE://" & Cstr(sTarget))
      set oDACL = oTargetSD.DiscretionaryACL
      
      For Each oACE in oDACL
      	If sAccount = "" or UCase(sAccount) = UCase(oACE.Trustee) Then 
      		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 iTarget = 0 Then
      			If (oACE.AccessMask AND FILE_READ_DATA) Then
      				sAccessMask = String(iOffset, Chr(32)) & "FILE_READ_DATA" & vbCrLf
      				hAccessMask = hAccessMask + FILE_READ_DATA
      			End If
      			If (oACE.AccessMask AND FILE_WRITE_DATA) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_WRITE_DATA" & vbCrLf
      				hAccessMask = hAccessMask + FILE_WRITE_DATA
      			End If
      			If (oACE.AccessMask AND FILE_APPEND_DATA) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_APPEND_DATA" & vbCrLf
      				hAccessMask = hAccessMask + FILE_APPEND_DATA
      			End If
      			If (oACE.AccessMask AND FILE_READ_EA) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_READ_EA" & vbCrLf
      				hAccessMask = hAccessMask + FILE_READ_EA
      			End If
      			If (oACE.AccessMask AND FILE_WRITE_EA) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_WRITE_EA" & vbCrLf
      				hAccessMask = hAccessMask + FILE_WRITE_EA
      			End If
      			If (oACE.AccessMask AND FILE_EXECUTE) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_EXECUTE" & vbCrLf
      				hAccessMask = hAccessMask + FILE_EXECUTE
      			End If
      			If (oACE.AccessMask AND FILE_DELETE_CHILD) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_DELETE_CHILD" & vbCrLf
      				hAccessMask = hAccessMask + FILE_DELETE_CHILD
      			End If
      			If (oACE.AccessMask AND FILE_READ_ATTRIBUTES) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_READ_ATTRIBUTES" & vbCrLf
      				hAccessMask = hAccessMask + FILE_READ_ATTRIBUTES
      			End If
      			If (oACE.AccessMask AND FILE_WRITE_ATTRIBUTES) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_WRITE_ATTRIBUTES" & vbCrLf
      				hAccessMask = hAccessMask + FILE_WRITE_ATTRIBUTES
      			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
      			If (oACE.AccessMask AND SYNCHRONIZE) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "SYNCHRONIZE" & vbCrLf
      				hAccessMask = hAccessMask + SYNCHRONIZE
      			End If
      		End If
      
      		If iTarget = 1 Then
      			If (oACE.AccessMask AND FILE_LIST_DIRECTORY) Then
      				sAccessMask = String(iOffset, Chr(32)) & "FILE_LIST_DIRECTORY" & vbCrLf
      				hAccessMask = hAccessMask + FILE_LIST_DIRECTORY
      			End If
      			If (oACE.AccessMask AND FILE_ADD_FILE) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_ADD_FILE" & vbCrLf
      				hAccessMask = hAccessMask + FILE_ADD_FILE
      			End If
      			If (oACE.AccessMask AND FILE_ADD_SUBDIRECTORY) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_ADD_SUBDIRECTORY" & vbCrLf
      				hAccessMask = hAccessMask + FILE_ADD_SUBDIRECTORY
      			End If
      			If (oACE.AccessMask AND FILE_READ_EA) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_READ_EA" & vbCrLf
      				hAccessMask = hAccessMask + FILE_READ_EA
      			End If
      			If (oACE.AccessMask AND FILE_WRITE_EA) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_WRITE_EA" & vbCrLf
      				hAccessMask = hAccessMask + FILE_WRITE_EA
      			End If
      			If (oACE.AccessMask AND FILE_TRAVERSE) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_TRAVERSE" & vbCrLf
      				hAccessMask = hAccessMask + FILE_TRAVERSE
      			End If
      			If (oACE.AccessMask AND FILE_DELETE_CHILD) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_DELETE_CHILD" & vbCrLf
      				hAccessMask = hAccessMask + FILE_DELETE_CHILD
      			End If
      			If (oACE.AccessMask AND FILE_READ_ATTRIBUTES) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_READ_ATTRIBUTES" & vbCrLf
      				hAccessMask = hAccessMask + FILE_READ_ATTRIBUTES
      			End If
      			If (oACE.AccessMask AND FILE_WRITE_ATTRIBUTES) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "FILE_WRITE_ATTRIBUTES" & vbCrLf
      				hAccessMask = hAccessMask + FILE_WRITE_ATTRIBUTES
      			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
      			If (oACE.AccessMask AND SYNCHRONIZE) Then
      				sAccessMask = sAccessMask & String(iOffset, Chr(32)) & "SYNCHRONIZE" & vbCrLf
      				hAccessMask = hAccessMask + SYNCHRONIZE
      			End If
      		End If
      		sMsg = "ACE Permissions:" & String(iOffset - Len("ACE Permissions:"), Chr(32)) 
      		Select Case hAccessMask
      			Case adsFILE_FULL 	Wscript.Echo sMsg & "FULL CONTROL"
      			Case adsFOLDER_FULL 	Wscript.Echo sMsg & "FULL CONTROL"
      			Case adsFILE_CHANGE 	Wscript.Echo sMsg & "CHANGE"
      			Case adsFOLDER_CHANGE 	Wscript.Echo sMsg & "CHANGE"
      			Case adsFILE_READ 	Wscript.Echo sMsg & "READ"
      			Case adsFOLDER_READ 	Wscript.Echo sMsg & "READ"
      			Case adsFILE_NOACCESS 	Wscript.Echo sMsg & "NO ACCESS"
      			Case adsFOLDER_NOACCESS Wscript.Echo sMsg & "NO ACCESS"
      			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
      	End If
      Next
      
      WScript.Echo "Total ACE entries:" &_
      		String(iOffset - Len("Total ACE entries:"), Chr(32)) & oDACL.AceCount
      WScript.Echo "ACL revision:" &_ 
      		String(iOffset - Len("ACL revision:"), Chr(32)) & oDACL.ACLRevision
      
      End Sub
      
      '**************************************************
      '*** Subroutine recursing through content of folder (when setting permissions)
      '*** necessary to propagate permissions set on parent folder (per Q266461)
      '
      Public Sub RecurseACLs(sTarget, sAccount, sPermission)
      
      Dim oTarget		'object representing target folder or file
      Dim oSubfolders		'collection representing subfolders of target folder
      Dim oFiles		'collection representing files in target folder
      Dim oSubfolder		'object representing a subfolder (used for enumeration)
      Dim oFile		'object representing a file (used for enumeration)
      
      If oFSO.FileExists(sTarget) Then
      	Call SetACLs(sTarget, sAccount, sPermission)
      Else
      	Set oTarget = oFSO.GetFolder(sTarget)
      	WScript.Echo "Processing folder " & sTarget
      	Call SetACLs(oTarget.Path, sAccount, sPermission)
      
      	Set oFiles = oTarget.Files
      
      	'*** Apply permissions to files
      	For Each oFile in oFiles
      		WScript.Echo "Processing file " & oFile.Path
      		Call SetACLs(oFile.Path, sAccount, sPermission)
      	Next  
      
      	Set oSubFolders = oTarget.SubFolders
      
      	'*** Apply permissions to subfolders
      	For Each oSubFolder in oSubFolders
      		Call RecurseACLs(oSubFolder.Path, sAccount, sPermission)
      	Next
      
      	Set oSubFolders = Nothing
      	Set oFiles = Nothing
      
      End If
      
      End Sub
      
      '**************************************************
      '*** Subroutine applying permissions for specified account 
      '
      Sub SetACLs(sTarget, sAccount, sPermission)
      
      Dim hMask		'value representing Access Mask
      Dim hType		'value representing Access Type
      Dim oSID		'object representing SID of a Security Principal
      Dim oACE		'object representing ACE of target object
      Dim hSID		'hexadecimal representation of SID
      Dim oTarget		'object representing target folder or file
      Dim oTargetSD		'object representing security descriptor of target file or folder
      Dim oDACL		'object representing Discretionary Access Control List
      
      Select Case UCase(sPermission)
      	Case "FULL"
      		hType = ADS_ACETYPE_ACCESS_ALLOWED
      		If iTarget = 0 Then
      			hMask = adsFILE_FULL
      		Else
      			hMask = adsFOLDER_FULL
      		End If
      	Case "CHANGE"
      		hType = ADS_ACETYPE_ACCESS_ALLOWED
      		If iTarget = 0 Then
      			hMask = adsFILE_CHANGE
      		Else
      			hMask = adsFOLDER_CHANGE
      		End If
      	Case "READ"
      		hType = ADS_ACETYPE_ACCESS_ALLOWED
      		If iTarget = 0 Then
      			hMask = adsFILE_READ
      		Else
      			hMask = adsFOLDER_READ
      		End If
      	Case "NOACCESS"
      		hType = ADS_ACETYPE_ACCESS_DENIED
      		If iTarget = 0 Then
      			hMask = adsFILE_NOACCESS
      		Else
      			hMask = adsFOLDER_NOACCESS
      		End If
      	Case Else
      		Call DisplayUsage("ERROR: Incorrect permission type.")
      		WScript.Quit
      End Select
      
      set oTargetSD = oADsSecurity.GetSecurityDescriptor("FILE://" & Cstr(sTarget))
      set oDACL = oTargetSD.DiscretionaryACL
      
      For Each oACE in oDACL
      	If UCase(oACE.Trustee) = UCase(sAccount) Then
      		oDACL.RemoveACE oACE
      	End If
      Next
      
      Set oACE = CreateObject("AccessControlEntry")
      oACE.Trustee = sAccount
      oAce.AceType = hType
      oAce.AccessMask = hMask
      oACE.AceFlags = ADS_ACEFLAG_INHERIT_ACE Or ADS_ACEFLAG_UNKNOWN
      oDACL.AddAce oACE
      
      Call ReorderDACL(oDACL)
      
      oTargetSD.DiscretionaryACL = oDACL
      oADsSecurity.SetSecurityDescriptor oTargetSD
      
      End Sub 
      
      '**************************************************
      '*** Subroutine reordering the ACLs (per Q279682)
      '*** ACEs need to be properly ordered, since AddAce method does not perform ordering. 
      '*** If an access-allowed ACE appears before access-denied, a trustee will be granted access.
      
      '*** The preferred order of ACEs in a DACL is described in MSDN Library (at msdn.microsoft.com). 
      '*** For Windows 2000, ACEs should be arranged into two main groups - non-inherited and inherited.
      '*** Non-inherited ACEs should be listed first, followed by the inherited ones. Within each group
      '*** (non-inherited and inherited), 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 (including its properties)
      '*** - access-allowed ACEs that apply to the object itself
      '*** - access-allowed ACEs that apply to subobjects of the object (including its properties) 
      '***
      '*** Since the script does not affect inherited ACEs (it sets permission directly on target object)
      '*** they do not have to be rearranged. We only need to rearrange non-inherited ACEs
      
      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 oAllowDACL			'object representing list of non-Inherited Allow 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")
      
      '**************************************************
      '*** 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    
      		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 oAllowDACL
      	  oNewDACL.AddAce oACE
      Next 
      For Each oACE In oInheritedDACL
      	  oNewDACL.AddAce oACE 
      Next
      
      Set oInheritedDACL = Nothing
      Set oDenyDACL = Nothing
      Set oAllowDACL = Nothing
      
      '**************************************************
      '*** Set appropriate DACL revision level
      
      oNewDACL.AclRevision = oDACL.AclRevision
      
      '**************************************************
      '*** Reset the original DACL
      Set oDACL = Nothing
      Set oDACL = oNewDACL
      
      end Sub
      
      
      

Page 1 of 1


Comment and Contribute

Your name/nickname

Your email

(Maximum characters: 1200). You have characters left.