PowerShell Access Control Module 4.0 Preview Update

Posted: February 27, 2015 in PowerShell, Security
Tags: , , , , , ,

There’s a new version of the PAC 4.0 Preview available on the TechNet Script Repository. There’s still no official documentation in the new version, so I’ll briefly mention some of the changes below. If you missed it, the first post on the 4.0 preview is here:

Modification Cmdlets

The following cmdlets are now available:

  • New-AccessControlEntry
  • Add-AccessControlEntry
  • Remove-AccessControlEntry
  • Enable-AclInheritance
  • Disable-AclInheritance
  • Set-Owner
  • Set-SecurityDescriptor

Like in previous versions, these commands can be used to work with native .NET security descriptor objects (output from Get-Acl), PAC security descriptor objects (output from Get-SecurityDescriptor), or directly with a whole bunch of objects. Here are some examples of what I’m talking about:

Working with .NET Security Descriptor Objects

You’re probably familiar with using the native PowerShell and .NET commands to work with security descriptors. You do something like this:

$Acl = Get-Acl C:\powershell
$Ace = New-Object System.Security.AccessControl.FileSystemAccessRule(
 "ContainerInherit, ObjectInherit",
$Acl | Set-Acl

That’s a lot of work to add a single Allow ACE giving Everyone Write access. You can use the PAC module to shorten that code to this:

$Acl = Get-Acl C:\powershell
$Ace = New-AccessControlEntry -Principal Everyone -FolderRights Write
$Acl | Set-Acl

You can also just cut out the New-AccessControlEntry call completely, which would shorten the snippet to this:

$Acl = Get-Acl C:\powershell
$Acl | Add-AccessControlEntry -Principal Everyone -FolderRights Write
$Acl | Set-Acl

And finally, one more way to shorten that:

Get-Acl C:\powershell | Add-AccessControlEntry -Principal Everyone -FolderRights Write -Apply

When you use -Apply like that, the module will actually call Set-SecurityDescriptor, so you’re not just using native PowerShell and .NET commands at that point.

Working with PAC Security Descriptor Objects

This actually looks just like working with the .NET security descriptor objects, except you use Get-SecurityDescriptor instead of Get-Acl, and Set-SecurityDescriptor instead of Set-Acl.

Working With Objects Directly

You don’t even need to use Get-Acl/Set-Acl or Get-SecurityDescriptor/Set-SecurityDescriptor. There are a ton of .NET and WMI instances that the module knows how to work with. These commands would be valid:

# This defaults to enabling inheritance on the DACL, but the SACL can be controlled, too
dir C:\powershell -Recurse |
Enable-AclInheritance -PassThru |
Remove-AccessControlEntry -RemoveAllAccessEntries -Apply

# -Apply isn't necessary here because the input object isn't a security descriptor. -Force
# would stop it from prompting you before saving the security descriptor.
Get-Service bits | Add-AccessControlEntry -Principal Users -ServiceRights Start, Stop

Get-SmbShare share | Add-AccessControlEntry -Principal Everyone -AccessMask ([ROE.PowerShellAccessControl.Enums.ShareRights]::FullControl)

PacSDOption Common Parameter

Most of the commands in the module have a parameter named -PacSDOption. That’s how you control things like recursing through child items (where supported), getting the SACL, bypassing the ACL check (the -BypassAclCheck parameter from the last post doesn’t exist as a direct cmdlet parameter anymore). The parameter’s input is from the New-PacCommandOption cmdlet. Here’s an example:

# Get the DACL and SACL entries for C:\powershell, even if you don't have permission to view them
Get-AccessControlEntry C:\powershell -PacSDOption (New-PacCommandOption -BypassAclCheck -Audit)

# Get the DACL and SACL entries for C:\powershell and any child folders (even if long paths are there):
Get-AccessControlEntry C:\powershell -PacSDOption (New-PacCommandOption -Recurse -Directory)


The default formatting of a security descriptor now shows both the DACL and the SACL:


The module will also check for the existence of a hash table named $PacOptions, and change how ACEs are displayed depending on its value. For now, there’s a single display option ‘DontAbbreviateAppliesTo’ that let’s you control how the AppliesTo column is displayed on ACEs. Here’s an example of how to create the hash table and change the AppliesTo setting:


Remember that this is still a preview version, so you’ll probably come across some things that don’t work the way they’re supposed to. If you find a problem, have a question about how to do something, or have a suggestion, please either post a comment below or send me an e-mail (magicrohn -at- outlook.com). Since there’s no documentation yet, I really don’t have a problem answering any questions.

  1. SamB says:

    Hey Rohn,
    Just attended your session in PS Summit 2015. That was outstanding. Thanks for a great module.


    • Rohn Edwards says:


      I’m glad you enjoyed the session. Don’t forget to let me know if you have any issues or suggestions for the module (there are still some bugs and missing features).


  2. Kevin Zachry says:

    I really enjoyed both of your tracks at the PowerShell Summit 2015 where I first saw you demo this personally. Great stuff! I didn’t realize that I would need to use it so soon until I ran across an authorization issue using Set-ACL with a colleague. This module worked like a charm! Thanks for making it!

    • Rohn Edwards says:

      Awesome! I’m glad you found it useful. As always, let me know if you have any suggestions to make it better!

  3. Carl Chipman says:

    Rohn, thank you so very much for these tools. They’ve greatly reduced my workload. I had a question about the Get-EffectiveAccess cmdlet. In the Windows UI, when doing effective access lookups, you can select the “Include Group Membership” option. I found this useful when a user was getting his share permissions via one group (i.e. Domain Users), and the file system object permissions via another group. Is there any way to accomplish the same in your cmdlet?

    • Rohn Edwards says:

      I’m planning on adding the ability to check against additional groups and claims, so you will be able to say something like this (in version 4.0):
      PS> Get-PacEffectiveAccess \\server\share -Principal UserName -GroupClaims Group1, Group2

      That would give you effective access for the ‘UserName’ user with the groups they are already a member of, plus it would treat them as if they were in the ‘Group1’ and ‘Group2’ groups (even if they aren’t in those groups).

      That being said, are you talking about being able to see why a user isn’t being granted permission over an object? If so, the command should already do that. For version 3, use the -ListAllRights switch on a share path. It looks like version 4.0 currently has an issue with UNC file/folder paths that needs to be fixed, otherwise you’d use the -Detailed switch for the same functionality (there will be an alias so it matches the version 3 switch name).

  4. Carsten says:


    first of all great module!
    Please publish the source.


  5. Rohn Edwards says:

    Thanks! The source can be found here: https://github.com/rohnedwards/PowerShellAccessControl/tree/v4.0_devel/

    (It still needs to be cleaned up a ton, but I’ve been saying for months how I’d release the source, and now seems like as good a time as any)

  6. Sol Birnbaum says:

    Hey Rohn,

    Any update on conditional ACEs?


    • Rohn Edwards says:

      Not yet. If I were to throw something together this weekend, would you be willing to help me test it out?

  7. […] Sol Birnbaum on PowerShell Access Control Modu… […]

  8. Robert Praetorius says:

    PAC is a fine-looking piece of software and nicely and thoroughly put together, but. . .Get-EffectiveAccess seems to be missing a feature that’d be useful to me: it lists the same effective access with I’m running as admin or not. So I’ve cobbled together a cheezy little function that handles this for the corner case I’m interested in (letting whoami and SysInternals’ AccessChk do most of the work).

    function Test-Access
    [ValidateSet(‘Read’, ‘Write’)]
    process {
    $groups = @(whoami) + $(whoami /groups /fo csv `
    | ConvertFrom-Csv|?{($_.attributes -split ‘, ‘) -contains ‘Enabled group’}|%{$_.’Group Name’.Trim()})

    $accessList = @{}
    $mode = @(‘-‘ + $AccessRequested[0].ToString().ToLower())
    accesschk.exe -q -u @mode $FileName `
    | ForEach-Object `
    $startsWithPrintingChar, $accessType, $principal = ([regex]’\s+’).split($_, 3)
    if (!$startsWithPrintingChar -and $accessType -and $principal)
    $accessList[$principal] = $accessType
    return [bool]($accessList[$groups] | ?{$_})

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s