Hey, Scripting Guy! Can I Determine a Folder's Access Rights and Who Has Them?

Hey, Scripting Guy! Can I Determine a Folder's Access Rights and Who Has Them?

  • Comments 7
  • Likes
Share this post:

Hey, Scripting Guy! QuestionHey, Scripting Guy! I am trying to get a handle around the security of a folder on my computer. I need to be able to figure out a way to determine who has access and what those access rights are. I guess I could use the Icacls utility, but I prefer to use something that is native to Windows PowerShell so that I can work with the objects that are returned and not have to waste a bunch of time parsing text.

-- BH

Hey, Scripting Guy! AnswerHello BH,

Microsoft Scripting Guy Ed Wilson here. If you have friended me on Facebook, you know that today is my birthday. I am at the point where having a birthday is not necessarily a cause for celebration—the Scripting Wife has not made me a cake and ice cream or invited my friends over for a party. At least not in the last couple of years. But still, I would rather have a birthday than not have a birthday so I am in a good mood. In addition, with the Scripting Wife, one never knows what she may have up her sleeve for the occasion.

Back to your question. If you do not want to use the Icacls utility because it is not native to Windows PowerShell, the best tool to use to work with security on a folder is the Windows PowerShell Get-Acl cmdlet. When you use the Get-Acl cmdlet and give it the path to a folder, it returns an instance of the System.Security.AccessControl.DirectorySecurity object, which is documented on MSDN and is used to represent the access control and the audit security for a directory. It specifies the access rights for a directory and how access attempts are audited. The class represents each of the access and audit rights as a set of rules. The access rules are presented as instances of the System.Security.AccessControl.FileSystemAccessRule object and the audit rules are presented as instances of the System.Security.AccessControl.FileSystemAuditRule class.  

To retrieve the DirectorySecurity object using the Get-Acl cmdlet, you specify the path to the folder via the path parameter. This is seen here:

PS C:\> Get-Acl -Path C:\fso

    Directory: C:\

Path                       Owner                      Access
----                       -----                      ------
fso                        BUILTIN\Administrators     NWTRADERS\Administrato...

PS C:\>

You can see from the output that the Owner property is returned. The Access property is truncated and does not display all of the users who have access to the folder. You might decide to pipe the results to the Select-Object cmdlet and choose the Access property. When you use this technique, as seen here, the Access control information is still truncated:

PS C:\> Get-Acl -Path C:\fso | select-object access

Access
------
{System.Security.AccessControl.FileSystemAccessRule, System.Security.AccessC...


PS C:\>

If you pipe the result of the Select-Object cmdlet to the Format-List cmdlet and choose all of the properties, you will finally be able to see all of the information returned from the Access property. As seen here, however, the results are not what might be expected:

PS C:\> Get-Acl -Path C:\fso | select-object access | Format-List *

Access : {System.Security.AccessControl.FileSystemAccessRule, System.Security.A
         ccessControl.FileSystemAccessRule, System.Security.AccessControl.FileS
         ystemAccessRule, System.Security.AccessControl.FileSystemAccessRule...
         }

PS C:\>

To retrieve a list of the users who have access to the folder, you need to use the accessToString property because the access rights to the folder is stored as a series of FileSystemAccessRules. After you have piped the results to the Format-List cmdlet, you no longer have a DirectorySecurity object. You have a formatted textual representation of the underlying object. This is seen here:

PS C:\> Get-Acl -Path C:\fso | Format-List AccessToString

AccessToString : NWTRADERS\Administrator Allow  FullControl
                 BUILTIN\Administrators Allow  FullControl
                 BUILTIN\Administrators Allow  268435456
                 NT AUTHORITY\SYSTEM Allow  FullControl
                 NT AUTHORITY\SYSTEM Allow  268435456
                 BUILTIN\Users Allow  ReadAndExecute, Synchronize
                 NT AUTHORITY\Authenticated Users Allow  Modify, Synchronize
                 NT AUTHORITY\Authenticated Users Allow  -536805376

If you wish to write to a text file the list of people who have access to the folder, the above formatted list is quite acceptable. To write the users who have access to a text file, you can use the Out-File cmdlet as seen here:

PS C:\> Get-Acl -Path C:\fso | Format-List accessToString |
Out-File -FilePath c:\fso\fsoAcl.txt -Append
PS C:\>

When the above command is run, the following text file is seen:

Image of text file displayed when command is run

If you prefer to work with the folder in a more direct manner, you can use the Get-Acl cmdlet to retrieve the DirectorySecurity object, and you can store it in a variable. This is seen here:

PS C:\> $acl = Get-Acl -Path C:\fso
PS C:\> $acl

    Directory: C:\


Path                       Owner                      Access
----                       -----                      ------
fso                        BUILTIN\Administrators     NWTRADERS\Administrato...

PS C:\>

After you have the DirectorySecurity object stored in a variable, you can work directly with the underlying objects. This is shown here:

PS C:\> $acl = Get-Acl -Path C:\fso
PS C:\> $acl


    Directory: C:\


Path                       Owner                      Access
----                       -----                      ------
fso                        BUILTIN\Administrators     NWTRADERS\Administrato...

To examine the methods and properties that are available from the object we have stored in the $acl variable, we use the Get-Member cmdlet. This is seen here:

PS C:\> $acl | Get-Member


   TypeName: System.Security.AccessControl.DirectorySecurity

Name                            MemberType     Definition
----                            ----------     ----------
Access                          CodeProperty   System.Security.AccessControl...
Group                           CodeProperty   System.String Group{get=GetGr...
Owner                           CodeProperty   System.String Owner{get=GetOw...
Path                            CodeProperty   System.String Path{get=GetPath;}
Sddl                            CodeProperty   System.String Sddl{get=GetSddl;}
AccessRuleFactory               Method         System.Security.AccessControl...
AddAccessRule                   Method         System.Void AddAccessRule(Sys...
AddAuditRule                    Method         System.Void AddAuditRule(Syst...
AuditRuleFactory                Method         System.Security.AccessControl...
Equals                          Method         bool Equals(System.Object obj)
GetAccessRules                  Method         System.Security.AccessControl...
GetAuditRules                   Method         System.Security.AccessControl...
GetGroup                        Method         System.Security.Principal.Ide...
GetHashCode                     Method         int GetHashCode()
GetOwner                        Method         System.Security.Principal.Ide...
GetSecurityDescriptorBinaryForm Method         byte[] GetSecurityDescriptorB...
GetSecurityDescriptorSddlForm   Method         string GetSecurityDescriptorS...
GetType                         Method         type GetType()
ModifyAccessRule                Method         bool ModifyAccessRule(System....
ModifyAuditRule                 Method         bool ModifyAuditRule(System.S...
PurgeAccessRules                Method         System.Void PurgeAccessRules(...
PurgeAuditRules                 Method         System.Void PurgeAuditRules(S...
RemoveAccessRule                Method         bool RemoveAccessRule(System....
RemoveAccessRuleAll             Method         System.Void RemoveAccessRuleA...
RemoveAccessRuleSpecific        Method         System.Void RemoveAccessRuleS...
RemoveAuditRule                 Method         bool RemoveAuditRule(System.S...
RemoveAuditRuleAll              Method         System.Void RemoveAuditRuleAl...
RemoveAuditRuleSpecific         Method         System.Void RemoveAuditRuleSp...
ResetAccessRule                 Method         System.Void ResetAccessRule(S...
SetAccessRule                   Method         System.Void SetAccessRule(Sys...
SetAccessRuleProtection         Method         System.Void SetAccessRuleProt...
SetAuditRule                    Method         System.Void SetAuditRule(Syst...
SetAuditRuleProtection          Method         System.Void SetAuditRuleProte...
SetGroup                        Method         System.Void SetGroup(System.S...
SetOwner                        Method         System.Void SetOwner(System.S...
SetSecurityDescriptorBinaryForm Method         System.Void SetSecurityDescri...
SetSecurityDescriptorSddlForm   Method         System.Void SetSecurityDescri...
ToString                        Method         string ToString()
PSChildName                     NoteProperty   System.String PSChildName=fso
PSDrive                         NoteProperty   System.Management.Automation....
PSParentPath                    NoteProperty   System.String PSParentPath=Mi...
PSPath                          NoteProperty   System.String PSPath=Microsof...
PSProvider                      NoteProperty   System.Management.Automation....
AccessRightType                 Property       System.Type AccessRightType {...
AccessRuleType                  Property       System.Type AccessRuleType {g...
AreAccessRulesCanonical         Property       System.Boolean AreAccessRules...
AreAccessRulesProtected         Property       System.Boolean AreAccessRules...
AreAuditRulesCanonical          Property       System.Boolean AreAuditRulesC...
AreAuditRulesProtected          Property       System.Boolean AreAuditRulesP...
AuditRuleType                   Property       System.Type AuditRuleType {get;}
AccessToString                  ScriptProperty System.Object AccessToString ...
AuditToString                   ScriptProperty System.Object AuditToString {...

The Access property is a codeproperty. This means it was added by the Windows PowerShell team. To see what you can do with the Access property, pipe it to the Get-Member cmdlet. This is seen here:

PS C:\> $acl.Access | Get-Member


   TypeName: System.Security.AccessControl.FileSystemAccessRule

Name              MemberType Definition
----              ---------- ----------
Equals            Method     bool Equals(System.Object obj)
GetHashCode       Method     int GetHashCode()
GetType           Method     type GetType()
ToString          Method     string ToString()
AccessControlType Property   System.Security.AccessControl.AccessControlType...
FileSystemRights  Property   System.Security.AccessControl.FileSystemRights ...
IdentityReference Property   System.Security.Principal.IdentityReference Ide...
InheritanceFlags  Property   System.Security.AccessControl.InheritanceFlags ...
IsInherited       Property   System.Boolean IsInherited {get;}
PropagationFlags  Property   System.Security.AccessControl.PropagationFlags ...


PS C:\>

The Access property returns an instance of the System.Security.AccessControl.FileSystemAccessRule .NET Framework class. When you look at the Access property, it displays the following information:

PS C:\> $acl.Access


FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : NWTRADERS\Administrator
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited       : True
InheritanceFlags  : None
PropagationFlags  : None

FileSystemRights  : 268435456
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited       : True
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : InheritOnly

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited       : True
InheritanceFlags  : None
PropagationFlags  : None

FileSystemRights  : 268435456
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited       : True
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : InheritOnly

FileSystemRights  : ReadAndExecute, Synchronize
AccessControlType : Allow
IdentityReference : BUILTIN\Users
IsInherited       : True
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : Modify, Synchronize
AccessControlType : Allow
IdentityReference : NT AUTHORITY\Authenticated Users
IsInherited       : True
InheritanceFlags  : None
PropagationFlags  : None

FileSystemRights  : -536805376
AccessControlType : Allow
IdentityReference : NT AUTHORITY\Authenticated Users
IsInherited       : True
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : InheritOnly

 

Because the System.Security.AccessControl.FileSystemAuditRule class is returned as a collection, you can index directly into it. This is seen here:

PS C:\> $acl.Access[0]


FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : NWTRADERS\Administrator
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None


The IdentityReference property returns an instance of System.Security.Principal.NTAccount .NET Framework class. The members of this object are seen here:

PS C:\> $acl.Access[0].identityReference | Get-Member


   TypeName: System.Security.Principal.NTAccount

Name              MemberType Definition
----              ---------- ----------
Equals            Method     bool Equals(System.Object o)
GetHashCode       Method     int GetHashCode()
GetType           Method     type GetType()
IsValidTargetType Method     bool IsValidTargetType(type targetType)
ToString          Method     string ToString()
Translate         Method     System.Security.Principal.IdentityReference Tra...
Value             Property   System.String Value {get;}


The IdentityReference property points to a specific user account. You can use that property to return a list of all the users who have access to a folder. When you query the Value property, it returns a string. This is seen here:

PS C:\> $acl.Access | ForEach-Object { $_.identityReference.value }
NWTRADERS\Administrator
BUILTIN\Administrators
BUILTIN\Administrators
NT AUTHORITY\SYSTEM
NT AUTHORITY\SYSTEM
BUILTIN\Users
NT AUTHORITY\Authenticated Users
NT AUTHORITY\Authenticated Users
PS C:\>

If you wanted to search the list of users for a specific user who has rights, you could pipe the results to the Where-Object. This is seen here:

PS C:\> $acl.Access | ForEach-Object { $_.identityReference.value |
Where-Object { $_ -eq 'nwtraders\administrator' }  }
NWTRADERS\Administrator
PS C:\>

Well, BH, this brings us to the end of another Hey, Scripting Guy! post. We hope we have inspired you to fire up Windows PowerShell and start playing around with the Get-Acl cmdlet.

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post them on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Excellent useful script thankyou....does anyone know how to get this to work for recursive paths so I can query an entire logical drive for NTFS permissions (folders only). Im pretty  new to powershell and attempted the following

    $Folders = Get-ChildItem c:\scripts\test123 -recurse  | where-object {$_.PsIsContainer}

    foreach ($folder in $folders) {

    $acl = get-acl $folder

    $acl.Access | select fileSystemRights, IsInherited, IdentityReference  | where {$_.IdentityReference -eq 'BUILTIN\users'} |

    select  Filesystemrights, IsInherited, IdentityReference

    }

    This is the output you get....seems to replace certain permissions with numbers ?

                                        FileSystemRights                                          IsInherited IdentityReference                                  

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

                                             -1610612736                                  BUILTIN\Users                                      

                             ReadAndExecute, Synchronize                                       False BUILTIN\Users                                      

  • Hi,

    Yes we are also seeing negative numbers this shows as "Special" in the UI -536805376

    Which when you open includes most permissions set to allow however obviously a bitwise AND doesn't return that this as having any allowed permissions.

    Very strange, this occurs both using the .NET methods and also using WMI

    Thanks,

    David

    CENTREL Solutions

    centrel-solutions.com/xiaconfiguration

  • The numbers that you see instead of permission descriptions are from files/folders that have had "generic" permissions applied to them. For some reason the .NET team didn't think to handle this scenario when getting the FileSystemRights property of an AccessRule (which seems odd as a lot of the default folders in a fresh Windows build have these generic permissions applied so it is not as if it is uncommon). I've explained how you can work out what these permissions actually are in my blog post here: permissions-not-included-in-net-accessrule-filesystemrights-enum

  • The link in my last comment doesn't seem to have pasted properly, here it is again: cjwdev.wordpress.com/.../permissions-not-included-in-net-accessrule-filesystemrights-enum

    Hopefully that worked...

  • This is great! - now how would we exclude certain groups based on 'contains this string' to filter out admin groups say that we dont care about, then go further to list the usernames of each group with what access they have listed next to each user?

  • @SISI - wow! great idea. Can you post your solution?

    Of course you realize that this is a four year old blog post.  I don't really think it is relevant anymore.  You?

    The forum for this blog is here: social.technet.microsoft.com/.../threads

    Start a question.  I am sure some people will remember those old issues from the last century, decade, millenium.

  • Awesome post. Thanks.