Today I want to go over one of the functions in the module that I published to the Script Center: Get-AccessControlEntry.
This function is meant to be used for auditing of access control entries (ACEs) in access control lists (ACLs). Right now, it is geared towards discretionary ACLs (DACLs), or the ACLs that control access to objects. It will work with system ACLs (SACLs), or the ACLs that control auditing of objects, in objects returned from Get-Acl with the -Audit switch, but the ACEs returned have at least one different property name from an ACE in a DACL, so the default formatting of the results doesn’t work properly. For now, I suggest just using it to audit DACLs. All of the other functions that deal with ACLs and ACEs in the module are currently geared towards DACLs, but I plan to fix that in a future release if anyone besides myself shows interest. When/if that happens, I’ll have hopefully come up with a solution that allows this function to better work with SACLs.
So, how does it work? The short answer is that it expands the ACE objects found in the ACLs of a security descriptor (SD) object, and it adds the path of the original object to each ACE. It really becomes useful when you feed it more than one object, and you get all of the ACEs expanded. I’ll go over some examples of that after covering the command syntax.
Let’s see how to use it:
PS> Get-Command Get-AccessControlEntry -Syntax
Get-AccessControlEntry [-Path ] [-AclType ] [-Filter ] [-Recurse]
[-AceInherited] [-AceNotInherited] []
Get-AccessControlEntry [-AclObject ] [-AclType ] [-Filter ] [-AceInherited]
[-AceNotInherited] []
So, there are two ways to call the function: you can pass it a path, or you can directly pass it an SD object. Let’s go over each of the parameters unique to each ParameterSet, then we’ll cover the common parameters that you can use for either type of call.
- ByPath Parameters:
- Path – A path to an object that will work with Get-Acl. Anything passed to this parameter is simply passed to Get-ChildItem, and Get-Acl is called on the object(s) returned.
- Recurse – Passes the -Recurse switch to Get-ChildItem for the path provided in the -Path parameter.
- ByAclObject Parameters:
- AclObject – A security descriptor object. The ACEs will be extracted from properties named in the -AclType parameter (if the -AclType parameter isn’t specified, the default values are used)
- Common Parameters:
- AclType – This is a list of properties to attempt to expand from the AclObjects. By default, the list contains the following strings:
- Access – The property on a security descriptor returned from Get-Acl that contains the DACL
- Audit – The property on a security descriptor returned from Get-Acl that contains the SACL
- DiscretionaryAcl – The property on a security descriptor object returned from New-AdaptedSecurityDescriptor that contains the DACL
- SystemAcl – The property on a security descriptor object returned from New-AdaptedSecurityDescriptor that contains the SACL
- Filter – A script block that filters the ACEs. The script block must evaluate to true in order for the ACE to be returned. You can use $_ to refer to the ACE object.
- AceInherited and AceNotInherited – These switches add on to the script block defined in the -Filter parameter to control which ACEs are displayed. They either show only ACEs that are inherited or only ACEs that aren’t inherited.
Here is a very brief demo script. Run a few of these commands to see a sampling of what you can do with the function:
# Show the ACEs on the Windows folder (format results as a table): Get-Acl C:\Windows | Get-AccessControlEntry | ft # Same thing, but pipe the results to Out-GridView so you can sort # them as you please: Get-Acl C:\Windows | Get-AccessControlEntry | Out-GridView # Get the ACEs for any IdentityReferences that have the word 'Users' # in them: Get-Acl C:\Windows | Get-AccessControlEntry -Filter { $_.IdentityReference -match "Users" } # Files under the Windows folder, only showing inherited # ACEs (different display this time): dir C:\Windows -File | % { Get-Acl $_.PsPath } | Get-AccessControlEntry -AceInherited | Sort-Object Path, AccessControlType, IdentityReference | Format-Table -GroupBy Path -Property AccessControlType, IdentityReference, FileSystemRights # If you change -AceInherited above to -AceNotInherited, you'll get a # listing of all ACEs that aren't inherited. # View the restriction policy for component access ACEs: New-AdaptedSecurityDescriptor -BinarySD (gp HKLM:\SOFTWARE\Microsoft\Ole).MachineAccessRestriction | Get-AccessControlEntry | Out-GridView <# View the namespace security on the root/cimv2 WMI namespace: NOTE: This must be run from an elevated prompt. Also, there is a bug in the WMI methods that are used to convert the Win32SD to SDDL or binary forms that causes the inheritance flags to not show properly. That's a pretty big issue, and I plan to take that into account if anyone uses the module. #> Get-CimInstance __SystemSecurity | Get-Win32SecurityDescriptor -Sddl | New-AdaptedSecurityDescriptor | Get-AccessControlEntry | Out-GridView # Use this to get a list of WMI classes that you can use # Get-Win32SecurityDescriptor against: Get-CimClass -MethodName GetSecurityDescriptor # Get WSMan ACEs: dir WSMan:\localhost -Recurse | Where Name -eq Sddl | ForEach-Object { New-AdaptedSecurityDescriptor -Sddl $_.Value -Path $_.PsPath -AccessMaskEnumeration ([PowerShellAccessControl.WsManAccessRights]) } | Get-AccessControlEntry | Sort-Object Path | Format-Table -GroupBy Path -AutoSize
Try it out, and let me know what you do or don’t like about it.