SetACL.exe: Set Windows NT/2000/XP permissions (DACLs) on virtually anything

SetACL.exe is a free program for setting permissions on Windows NT/2000/XP systems. I started developing it in early march 2001, when I needed a program that could set permissions on printers, but could not find one. I learned that setting permissions programmatically on printers is basically the same as on files, directories, registry keys, services, and so on.
SetACL is supposed to be fast. If it is not really fast (slow, maybe?) on your system, please check your name resolution settings (WINS, DNS, etc.). If it still does not behave, please contact the author (see bottom of page).



This Site Has Moved

This site has moved. Please go to helgeklein.com for information on SetACL or Helge Klein.

New Version 2.0 available

A new, very much extended and completely rewritten version 2.0 of SetACL is available. The new version is published under the GPL; the project home page can be found here. The new version has a "list" function and will be available as an ActiveX-DLL.

I will NOT continue to work on version 0.904. This page remains online for reference purposes.

Table of contents



Revision history

  • 0.904, 09/25/2002
    • Fixed bug number 4.
    • Added the parameter "/silent". Using this, no output will be displayed.
  • 0.903, 08/30/2002
    • Fixed a bug: the option "/man_docs" for printers did not set "manage documents" permissions correctly (thanks to Ryan B.).
  • 0.902, 06/27/2002
    • The option "/i:inh_only" did not work as planned (thanks to Christopher H.). I changed it into three different modes: inh_only_obj, inh_only_cont and inh_only_cont_obj. This corresponds to what can be set in Windows ACL editor (i.e. in Explorer).
  • 0.901, 02/12/2002
    • Permissions can now be set on the root of a drive (i.e. "C:\" or "\\servername\c$"). This was not possible previously.
    • When trying to set permissions on a non-existent file system path, now the correct error message is displayed (previously only a general error message appeared).
  • 0.90, 01/10/2002
    • With the optional argument "/sid" trustees (the user/group you want to set the permission for) can be specified using their SID. Thus when setting permissions for built-in users/groups like "Administrators" language independence can be achieved by using their so called well-known-SID.
    • The full range of registry permissions is now supported. Before, only "read" and "full" were available.
    • Wildcards can be used in the file system. For example setting permissions on "C:\Data\Users\Mi*" is now possible.
    • The parameter "/p" (inherit from parent) has been extended: when setting this to "no" you can choose whether to copy the permissions from the parent object or whether to clear the ACL and start from scratch just like in the Windows GUI.
    • Permissions can now be set on any remote machine in any remote domain as long as it is reachable and you have the appropriate permissions yourself. Before, SetACL worked only on machines in the same or in trusted domains. Thanks to Adam S.
  • 0.88, 05/22/2001
    • Added recursion for registry keys. This is more important for NT4 than for W2K users. Please note that because of limitations (which might be overcome in a future version) of the underlying Win32-API only subkeys of HKLM and HKU can be set on remote machines. Please keep in mind, that this is not really a limitation of SetACL, for (to my limited knowledge) every single registry key can be reached via aforementioned root keys.
  • 0.879, 05/18/2001
    • Added a parameter (/r) to recursively set permissions on files, dirs and files + dirs. This is generally only necessary on NT4 systems. Windows 2000+ propagates permissions down the directory tree all by itself.
      ATTENTION: There seems to be a bug in Windows 2000 (or in SetACL ;-) that causes revoking permissions which were set with the option /i:no_prop_inh to fail! It does work on NT4, though. I will investigate this further.
  • 0.871, 05/16/2001
    • Fixed a bug which made it necessary to have a runtime DLL on your system (MSVCP60.DLL). On NT4 systems, this is not the case if not too much newer software is installed. Now, the necessary libraries are linked statically, which makes the program somewhat bigger.
  • 0.87, 04/20/2001
    • Fixed a bug when denying permission on files/dirs, where the SYNCHRONIZE bit was also denied. This caused the file/folder to be unaccessible. Thanks to Martin S.
  • 0.86, 04/04/2001
    • Inheritance is now an optional argument, as it should have been from the beginning
    • Inheritance from the parent object can be blocked
    • Fixed a bug that made it really difficult to revoke permissions on newly created printers that were set by the OS (ie. for EVERYONE)
  • 0.85, 03/26/2001, Added support for network shares
  • 0.80, 03/24/2001, Added support for registry keys and services
  • 0.70, 03/22/2001, First published version


News and changes

  • 02/13/2003
    • A completely new and very much extended version 2.0 of SetACL is currently nearing beta stage. I have incorporated all features that have been requested and much more! There will be a command line version and also an ActiveX DLL for all who are using SetACL in (Perl, VBS, other) scripts or programs.
  • 09/25/2002
    • Version 0.904 is available.
  • 08/30/2002
    • Version 0.903 is available.
  • 06/27/2002
    • Version 0.902 is available.
  • 02/12/2002
    • Version 0.901 is available.
    • A Section "Known Bugs" has been added.
  • 01/10/2002
    • Version 0.90 is finally available. Several new features have been added (SIDs can be used, Wildcards are supported in the file system, all existing registry permissions are available, etc.).
  • 08/15/2001
    • Announcement: I am working on version 0.90 which will include several new features. Please be patient, I do have a full time job, a lot of friends, and so on...
      New features include:
      • Use SIDs in parameter "trustee". This allows you to use so called (language independent) well-known-SIDs.
      • Use wildcards in file system and registry paths. For example, you will be able to set ACLs on "C:\Data\Users\Helge*", which sets ACLs on every user directory beginning with "Helge".
      • If you have suggestions for even more new features, please contact me (address at bottom of page).
  • 05/24/2001
    • ATTENTION: There is a bug in NT4 which causes SetACL to change/remove ACEs (Access Control Entries) set in NT4 Explorer. The effects of the bug depend on the service pack installed, but it seems to occur even with SP6a. It can be reproduced like this:
      • Create a new directory like "C:\Test".
      • Open the permissions tab in NT4 explorer. Add any local group with any type of access, for example "everyone" and "full control". Remove all other entries (this is not really necessary). Click OK.
      • Run SetACL with standard options for any other local group, ie.:
        SetACL c:\test /dir /set users /change
      • Check the permissions in Explorer. Only the group set by SetACL remains.
      Background: I use the function SetEntriesInAcl from the Win32 API to merge the new ACE into the existing ACL for the object. According to several newsgroups (do a search on 'SetEntriesInAcl' on 'groups.google.com') this is an old bug in NT4. SetEntriesInAcl is a high-level function which could be replaced only by a large amount of code using low-level functions. If I were to replace SetEntriesInAcl, I would have to rewrite a crucial part of the program, which would possibly introduce new bugs and/or problems. Additionally, I have written SetACL to be used primarily with W2K where this bug does not occur. Please excuse me for not working around this.
      Workaround: Set your permissions either with SetACL or with Explorer, but never use both.
  • 05/22/2001
    • Added recursion for registry keys.
  • 05/18/2001
    • Option /r added to recursively set permissions on every object in a directory tree. You can specify whether to apply permissions on files only, directories only, or files and directories.
    • SetACL now incorporates all needed libraries, which fixes a bug on NT4 systems where a message appeared stating a DLL was missing. The program got somewhat fatter, though.
  • 04/18/2001
    • Examples added
    • Table of contents added
    • Added explanation of "inherit from parent"
    • When setting permissions on local groups on your local machine, you must not specify the 'machine' part of the trustee. Thanks to Nathan K.
    • To my great pride Jerold Schulman mentions SetACL.exe on his extensive list of Windows NT/2000 tips and tricks as tip 3583. His list of tips can be found at: www.jsiinc.com.


Known Bugs

  1. NT4: Certain builtin groups like "Interactive" cannot be used
    SetACL behaves like everything worked fine, but permissions are not set. This has been confirmed for registry permissions. This might be caused by bugs in the implementation of the high level security API which is used by SetACL.
  2. NT4 / Windows 2000: Most registry permissions set by the system cannot be removed with SetACL
    This affects NT4 and W2k. It happens because most permissions set by the system consist of two ACEs for one trustee. The two ACEs have different inheritance settings and permissions. The API function used to merge existing permissions of an object with the new permissions specified is seemingly not capable of handling such a scenario.
  3. NT4: SetACL changes/removes ACEs set in Explorer
    The effects of the bug depend on the service pack installed, but it seems to occur even with SP6a. It can be reproduced like this:
    • Create a new directory like "C:\Test".
    • Open the permissions tab in NT4 explorer. Add any local group with any type of access, for example "everyone" and "full control". Remove all other entries (this is not really necessary). Click OK.
    • Run SetACL with standard options for any other local group, ie.:
      SetACL c:\test /dir /set users /change
    • Check the permissions in Explorer. Only the group set by SetACL remains.
    Background: I use the function SetEntriesInAcl from the Win32 API to merge the new ACE into the existing ACL for the object. According to several newsgroups (do a search on 'SetEntriesInAcl' on 'groups.google.com') this is an old bug in NT4. SetEntriesInAcl is a high-level function which could be replaced only by a large amount of code using low-level functions. If I were to replace SetEntriesInAcl, I would have to rewrite a crucial part of the program, which would possibly introduce new bugs and/or problems. Additionally, I have written SetACL to be used primarily with W2K where this bug does not occur. Please excuse me for not working around this.
    Workaround: Set your permissions either with SetACL or with Explorer, but never use both on NT4.
  4. Windows 2000: permissions set with "/i:no_prop_inh" cannot be revoked
    There seems to be a bug in Windows 2000 (or in SetACL ;-) that causes revoking permissions which were set with the option "/i:no_prop_inh" to fail. It does work on NT4, though.
    Fixed in version 0.904. Thanks to Ruudy v. L.


Features

SetACL is relatively feature complete and bug free. SetACL has been fast and stable from the very beginning!

SetACL can set permissions on:
  • Local or remote directories
  • Local or remote files
  • Local or remote printers
  • Local or remote registry keys
  • Local or remote Win32 services
  • Local or remote network shares
The following special features distinguish SetACL from similar programs:
  • Use all special permissions of Windows 2000 in the file system and in the registry.
  • Block the inheritance from the parent object while copying the ACL from the parent object or clearing it.
  • Specify how permissions are inherited to child objects: container, object or container + object.
  • Set permissions for any type of user or local / domain local / global / universal group.
  • Set permissions on any machine; it does not matter whether the target machine is in a trusted domain, an independent domain or a workgroup.
  • Use wildcards in object names (only works in the file system).
  • Recursively set permissions on any sub-object in the file system and in the registry.
  • Set, grant, deny or revoke permissions.


SetACL.exe is a Win32 console program. It's actions are controlled by command line parameters. It always returns a return code, which can be one of the following:
  • 0 for successful execution
  • 1 if usage instructions were printed (when invoked without or with erraneous arguments)
  • 2 if an error condition occured


Usage is as follows:
SetACL.exe 0.904   by Helge Klein             www.helge.mynetcologne.de/setacl

Usage: SetACL.exe <object name> <object type> <action> <trustee> <permissions>
                  [/i:<inheritance>] [/p:<inh. from parent>] [/r:<recursion>]
                  [/sid] [/silent]

==============================================================================

<object name>   = Any valid path to local or remote object

------------------------------------------------------------------------------

<object type>   = {/file | /dir | /printer | /registry | /service | /share}

------------------------------------------------------------------------------

<action>        = {/deny | /grant | /set | /revoke}

------------------------------------------------------------------------------

<trustee>       = User/group to grant/deny permissions for, ie. 'machine\user'

------------------------------------------------------------------------------

<permissions>

      /file       = {/read | /write | /read_ex | /change | /full | /traverse |
                     /list_dir | /read_attributes | /read_ea | /add_file |
                     /add_subdir | /write_attributes | /write_ea |
                     /delete_child | /delete | /read_dacl | /write_dacl |
                     /write_owner}

      ........................................................................

      /dir        = {/read | /write | /list_folder | /read_ex | /change |
                     /profile | /full | /traverse | /list_dir |
                     /read_attributes | /read_ea | /add_file | /add_subdir |
                     /write_attributes | /write_ea | /delete_child |/delete |
                     /read_dacl | /write_dacl | /write_owner}

      ........................................................................

      /printer    = {/print | /man_printer | /man_docs | /full}

      ........................................................................

      /registry   = {/read | /full | /query_val | /set_val | /create_subkey |
                     /enum_subkeys | /notify | /create_link | /delete |
                     /write_dacl | /write_owner | /read_access}

      ........................................................................

      /service    = {/read | /start_stop | /full}

      ........................................................................

      /share      = {/read | /change | /full}

------------------------------------------------------------------------------

<inheritance>  = {cont_obj_inh | cont_inh | obj_inh | no_prop_inh |
                  inh_only_obj | inh_only_cont | inh_only_cont_obj}

------------------------------------------------------------------------------

<inh. from parent>
               = {yes | no_copy | no_dont_copy}

------------------------------------------------------------------------------

<recursion>    = {cont_obj | cont | obj}

(Only for reg keys and directories) Walk down the tree and set permissions on
every key, directory and every file {cont_obj}, on every key and directory
{cont}, or on every file {obj}. Only needed on NT4 and in special cases.

------------------------------------------------------------------------------

/sid           : <trustee> parameter is a SID, not an account/group name.
                 Well-known SIDs can be used.

------------------------------------------------------------------------------

/silent        : No output whatsoever is displayed if the number of
                 parameters passed is correct.

==============================================================================

If not specified, inheritance is always set to values which suit the cause.
Using your own settings can result in undesired permissions. Beware!

Also, 'inherit from parent' is set to 'yes' if not specified.


Examples:
SetACL.exe "C:\My Dir\My File" /file /set localgroupname /read

           Sets read permissions on a file on local drive C: for a local group
           called "localgroupname".

SetACL.exe \\servername\MACHINE\software /registry /grant S-1-1-0 /read /sid

           Grants (adds) read permissions on the registry key HKLM\software on server
           "servername" for a user/group represented by its SID, which is in this case
           "Everyone". This SID is a so called well known SID which is identical on
           every system.

SetACL.exe \\servername\sharename /dir /set domainname\domaingroup /profile

           Sets the permissions needed for a Windows 2000 roaming profile folder
           on server "servername" for a directory (!) accessible through share
           "sharename" for a domain group called "domaingroup" in domain "domainname".

SetACL.exe \\servername\sharename\dirname /dir /set servername\username /change

           Sets change permissions on a directory "dirname" on server "servername"
           accessible through the UNC path "\\servername\sharename\dirname" for a
           user "username" local to server "servername".


Remarks

The "object name" parameter:
  • Files/directories: Can be a relative path ("filename"), absolute path ("c:\dirname") or a UNC name ("\\machine\share\dirname").
  • Printers: Can be a local ("printername") or a remote printer ("\\machine\printername")
  • Registry key: Can be a local ("MACHINE\MyKey") or a remote registry key ("\\machine\MACHINE\MyKey").
    The hive keys must be specified like this: "CLASSES_ROOT", "CURRENT_USER", "MACHINE", "USERS".
  • Service: Can be a local ("servicename") or a remote service ("\\machine\servicename").
  • Share: Can be a local or remote network share. Always specify: "\\machine\share".
The "action" parameter:
  • "/grant": Creates a new access-allowed ACE that combines the specified rights with any existing rights of the trustee. The new ACE replaces any existing access-allowed ACE for the trustee. The program also modifies or deletes any existing access-denied ACE for the trustee that denies the specified rights.
  • "/set": Similar to /grant except that the new access-allowed ACE allows only the specified rights, discarding any existing rights. This flag also removes any existing access-denied ACE for the trustee.
  • "/deny": Creates a new access-denied ACE that replaces any existing access-denied ACE for the trustee. The new ACE denies the specified rights in addition to any currently denied rights of the trustee. The program also modifies or deletes any existing access-allowed ACE for the trustee that allows the specified rights.
  • "/revoke": Removes any existing ACEs for the specified trustee. The program ignores the rights specified.
  • The action parameters can be abbreviated by using only the first letter, ie. "/g" instead of "/grant".
The "trustee" parameter:
  • This is the user or group you want to set the permission for.
  • It can be a any type of local or domain user or group (local/domain user, local group, domain local group, global group or universal group).
  • Always use the format 'machine\user' or 'domain\user'. If you want to set permissions for a local group on your local machine, please omit the 'machine\' part.
  • You can use predefined groups, like "EVERYONE" or "GUEST". If you do this, a machine name should not be specified.
  • The following special names can be used:
    • "CREATOR GROUP": This is used in conjunction with inheritance. When a new object is created, the system replaces this SID with the primary group SID of the user who created the object.
    • "CREATOR OWNER": This is used in conjunction with inheritance. When a new object is created, the system replaces this SID with the SID of the user who created the object.
    • "CURRENT_USER": Indicates the owner of the calling thread or process.
  • If the optional parameter "/sid" is used the trustee is expected to be a SID (security ID). This can be very useful if you want to set permissions for generic (built-in) users or groups in a language independent way. Example: on an english machine the administrators group is called "Administrators"; on a german machine it is called "Administratoren". Hint: the SIDs of generic users/groups are always the same, regardless of OS type or language. A list of generic SIDs can be found here.
The "permissions" parameter:
  • The permissions you can set on files, directories and registry keys correspond to the standard and special permissions of Windows 2000.
  • I added a set of permissions of my own, "/profile", which sets the permissions needed for a user profile folder on Windows 2000, which are "change" + "set permissions".
  • The permissions you can set on printers, network shares, services and correspond to the standard permissions of Windows 2000.
The "inheritance" parameter:
  • Use this with extreme caution, especially on production machines!
  • The correct (standard) inheritance flags are always set for you. If you need to, you can use this parameter to specify special, non-standard inheritance flags.
  • If you set permissions on a container (for example, a directory) that contains sub-containers and/or objects, permissions are propagated down the tree.
  • The following flags can be used:
    • "/cont_obj_inh": Both container and noncontainer objects that are contained by the specified container inherit the ACE in addition to the container specified.
    • "/cont_inh": Other containers that are contained by the specified container inherit the ACE in addition to the container specified.
    • "/obj_inh": Noncontainer objects contained by the specified container inherit the ACE in addition to the container specified.
    • "/inh_only_obj": The ACE does not apply to the specified container to which the ACL is applied, but objects contained by the specified container inherit the ACE.
    • "/inh_only_cont": The ACE does not apply to the specified container to which the ACL is applied, but containers contained by the specified container inherit the ACE.
    • "/inh_only_cont_obj": The ACE does not apply to the specified container to which the ACL is applied, but containers and objects contained by the specified container inherit the ACE.
    • "/no_prop_inh": The ACE is not propagated down to lower level objects/containers.
The "inherit from parent" parameter:
  • "yes": This object inherits permissions from its parent objects. This is the normal setting for any type of object. If you do not specify this optional argument, "yes" is always assumed.
  • "no_copy": This object blocks permissions from its parent objects. The permissions from the parent object are copied to the object specified and then the permissions are set.
  • "no_dont_copy": This object blocks permissions from its parent objects. The permissions from the parent object are NOT copied to the object specified which results in an ACL that contains only the permissions set with SetACL.
The "recursion" parameter:
  • (Only for registry keys and directories) Walk down the tree and set permissions on every key/directory/file. This is only needed on NT4 and in special cases since Windows 2000 progagates permissions down the tree all by itself.
  • "cont_obj": Recursively set permissions on every container (registry keys and directories) and object (files).
  • "cont": Recursively set permissions ONLY on containers (registry keys and directories).
  • "obj": Recursively set permissions ONLY on objects (files).
The "/sid" parameter:
  • If the optional parameter "/sid" is used the trustee is expected to be a SID (security ID). This can be very useful if you want to set permissions for generic (built-in) users or groups in a language independent way. Example: on an english machine the administrators group is called "Administrators"; on a german machine it is called "Administratoren". Hint: the SIDs of generic users/groups are always the same, regardless of OS type or language. A list of generic SIDs can be found here.
The "/silent" parameter:
  • If the optional parameter "/silent" is used no output will be generated if the number of parameters passed to the program is correct. This can be useful if SetACL is used in batch files or from scripts. Successful execution can be checked using the return value which is always set.


Download

You can download the program here.

License

SetACL.exe is free for everyone.

Contact

If you have found a bug or want to submit comments, suggestions or feature requests please note that this version is not supported any more. The current version of SetACL can be found on helgeklein.com.

My name is Helge Klein and I live in Cologne/Germany.