Posts Tagged ‘SACL’

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- Since there’s no documentation yet, I really don’t have a problem answering any questions.

There’s a new version of my PowerShellAccessControl module available in the Script Center Repository. It’s got a lot of new stuff in it, so go check it out. I’m going to just show you some random commands to run (and I’ll post a screenshot or two).

The update brings the ability to audit/modify SACLs (object auditing). It also simplifies getting security descriptors for several objects, including services, printers, WMI namespaces, and more (even file/folder and registry entries). PowerShell v2 is also supported (let me know if you find anything that doesn’t work when using v2). It’s still lacking the functions I’ve been working on to actually save the security descriptors back out. Don’t worry, though, because those are coming. I’m also working on other ways for the module to get its hands on more security descriptors.

For now, though, I think it does a pretty good job of letting you audit your ACLs for almost anything you’d want to (and if it doesn’t directly support the object, you can still use New-AdaptedSecurityDescriptor if you know the SDDL or binary form of the SD). You can also use New-AccessControlEntry to create file, folder, and registry ACEs to use with Get-Acl and Set-Acl. That by itself saves several lines of code.

Anyway, go download the module, then run through some of these demo scripts line by line:

Working with services:

# Must be run as admin b/c of GetSecurityDescriptor WMI method

# Get BITs service SD
$SD = Get-Service bits | Get-SecurityDescriptor

# Check out the default formatting

# And as a list:
$SD | fl

# Show ACEs (access and audit) for services that start with the letter 'B'
Get-Service b* | Get-AccessControlEntry

# Show auditing ACEs for services that start with the letter 'B'
Get-Service b* | Get-AccessControlEntry -AclType Audit

# Get BITs service SD (again)
$SD = Get-Service bits | Get-SecurityDescriptor

# Give users the ability to Start and Stop it:
$SD.AddAccessRule((New-AccessControlEntry -ServiceAccessRights Start, Stop -Principal Users))
# Audit that
$SD.AddAuditRule((New-AccessControlEntry -ServiceAccessRights Start, Stop -Principal Users -AuditSuccess))

# Look to make sure those entries are there:
$SD | fl

# Since there's no Set-SecurityDescriptor yet, do this if you want to save
# SD (you have to remove -WhatIf to make it permanent)
$Win32SD = $SD | ConvertTo-Win32SecurityDescriptor -ValueOnly  # Use -LegacyWmiObject if you're going to use WMI cmdlets
Get-CimInstance Win32_Service -Filter "Name='bits'" | Invoke-CimMethod -MethodName SetSecurityDescriptor -WhatIf -Arguments @{
    Descriptor = $Win32SD

Working with other objects:

# Printers
Get-WmiObject Win32_Printer | Get-SecurityDescriptor

# Printer access ACE:
$ACE = New-AccessControlEntry -PrinterRights ManageDocuments -Principal Users

# Logical share:
Get-CimInstance Win32_LogicalShareSecuritySetting | Get-SecurityDescriptor

# WSMan:
dir wsman: -Recurse | ? { $_.Name -eq "SDDL" } | Get-SecurityDescriptor

# Folder:
get-item c:\windows | Get-SecurityDescriptor
dir c:\windows -Directory | Get-AccessControlEntry -AceNotInherited
dir c:\windows -Directory | Get-AccessControlEntry -IdentityReference Administrators

# WMI namespace:
$SD = Get-CimInstance __SystemSecurity -Namespace root/cimv2 | Get-SecurityDescriptor

# Add an access ACE that also applies to all child namespaces:
$SD.AddAccessRule((New-AccessControlEntry -WmiNamespaceRights RemoteEnable -Principal Users -AppliesTo Object, ChildContainers))

# View the modified ACL:
# Get new SDDL:
# Get new binary form:

# Remember, WMI namespace SD hasn't been modified for real, just in in-memory instance of SD

Audit all WMI namespace rights:

function Get-ChildNamespace {

        [string] $Namespace = "root",
        [int] $Level = 1

    # Decrement level (if argument wasn't supplied, you'll only get
    # the direct chidren)

    Get-WmiObject __Namespace -Namespace $Namespace | select -exp name | ForEach-Object {

        [PsCustomObject] @{
            FullName = "$Namespace\$_"
            Name = $_
            Namespace = $Namespace

        # Negative numbers mean recurse forever
        if ($Level) {
            & $MyInvocation.MyCommand -Namespace "$Namespace\$_" -RecurseLevel $Level

# Store SDs for all namesapces in $WmiNsSD (gwmi)
$WmiSDs = Get-ChildNamespace -Level -1 | 
    select -exp fullname | 
    % {"root"}{ $_ } | 
    sort | 
    % { Get-WmiObject -EnableAllPrivileges __SystemSecurity -Namespace $_ } | 

# Just show with default formatting:

# Or show with ACEs expanded as their own objects
$WmiSDs | Get-AccessControlEntry

# Only show ACEs that aren't inherited:
$WmiSDs | Get-AccessControlEntry -AceNotInherited

And here is a screenshot showing the default formatting after calling ‘Get-Service b* | Get-AccessControlEntry’:

Get-Service b* | Get-AccessControlEntry

Get-Service b* | Get-AccessControlEntry

And one after calling ‘Get-Service bits | Get-SecurityDescriptor’

Get-Service | Get-SecurityDescriptor

Get-Service | Get-SecurityDescriptor

There are a lot of examples in the comment based help for the functions, too. If you have any issues/suggestions, please let me know.