How to enable "Replace all child object auditing entries..."?

Dear all,

I’ve to rollout NTFS Auditing to 30+ Windows file servers.

I wrote a small powershell script, that utilizes set-acl in order to set the relevant SACLs to the root folder of the server’s file share. The inherit and propagation flags are set properly in order to have this audit policy to be applied to “This folder, sub folder and files”.

Unfortunately the inheritance of several 1000 sub folders has been disabled in the past and the audit policy doesn’t has any effect on all directories below a certain level.

Although I searched the net for a solution, the last couple of days, I wasn’t able to find how I can enable the inheritance of audit policies for a folder using powershell. Of course, there are these “Enable inheritance” and “Replace all child object auditing entries with inheritable auditing entries from this object” options in the GUI of the advanced security dialogue, but since we’re talking about 30+ servers and in total several thousands of directories, there’s no point in doing this manually for each and every directory.

Long story short:
Is there any way, how I can get the same result I get when I activate the “Replace all child object auditing entries…” checkbox in GUI, via powershell?

Thanks in advance!

Have a good weekend!


While there might be an easier option, which I don’t know of, I would recommend you to watch the recording of Jaap Brasser’s sesion from this year’s European PowerShell conference Breakdown the GUI: PowerShell Logging To Automate Everything. This introduces several options on how to replicate GUI actions through PowerShell.
Hopefully this will point you in the right direction.

Please follow the below steps:

1. Start Explorer
2. Right click on the file or directory you want to audit and from the context menu select properties
3. Select the Security tab and click Advanced Auditing tab
4. Click the Add button and add the users who you wish to audit by selecting and clicking Add. When finished adding users, click OK
5. Select checkbox “Replace all child object auditing entries with inheritable auditing entries from this object”
6. Select the events you wish to audit and then click OK

For more information please refer to following MS articles:

How to audit user access of files, folders

Audit object access

Hope it helps

Thanks Edwin,

I’m aware that I can do this manually through the GUI using the way you described, but doing it manually isn’t what I want, since I would have to do this on each and every server. I’m looking speficically for a way to do what the “Replace all child audit entries” does via Powershell.

Thanks Dirk as well for pointing me towards the video, I’ll take a look at it.


The bad news: I don’t think you can do exactly what you’re asking with pure PowerShell. When you check that box, I’m pretty sure the GUI is calling either the TreeResetNamedSecurityInfo or TreeSetNamedSecurityInfo Win32 API functions, and I’m not aware of any cmdlets or .NET classes that will call that. To do it in PowerShell (without using P/Invoke to implement that function), you’ll have to walk the tree and do work on each security descriptor.

More bad news: I was trying to mock up some PS code to do a simple walking of the folder structure and ensuring that SACL inheritance was enabled, and it seems that the underlying .NET classes have some sort of issue with this when the SACL is null, and it doesn’t seem to honor turning the ACL protection off. I’ll include an example of what the steps to fix it with pure PowerShell should look like, along with an example of how to recreate the problem (please work through it just to make sure I’m not imagining things).

The good news: you can still do this with PowerShell if you’re willing to use a third party module (you can probably still do it with pure PowerShell/.NET if you track down why an empty and/or null SACL makes it so .NET won’t let you enable SACL inheritance). I’ve got a module you can download from here. It’s on GitHub here (there are two branches–one for 3.0 and one for 4.0). The 3.0 version is a script module, so you can open it up and see the source anytime, and the 4.0 is a compile module, so you’ll need to look at the GitHub page to see its source.

If you get v4.0, this should work:

$PacSdOption = New-PacSDOption -SecurityDescriptorSections Audit -Recurse -BypassAclCheck

$Root = 'c:\path\to\root'

# See the problem areas (this is optional):
Get-PacSecurityDescriptor $Root -PacSDOption $PacSdOption | 
    where AreAuditRulesProtected -eq $true | 
    Tee-Object -Variable BadSacls | 
    select Path, AreAuditRulesProtected

# Fix them:
Get-PacSecurityDescriptor $Root -PacSDOption $PacSdOption |
    select -Skip 1 | # You may want the $Root to have SACL inheritance disabled
    where AreAuditRulesProtected -eq $true | 
    Enable-PacAclInheritance -SystemAcl -PacSDOption $PacSdOption -Apply #-Force

    # NOTE: As the command is, you'll be prompted for each SACL before the change 
    #       is made. Uncommenting the -Force should fix that

This is the pure PowerShell way that should work, but doesn’t seem to work if the SACL is empty:

# Set up a tmp folder structure:
$TempRoot = mkdir "$env:temp\sacl_test"
$Child = mkdir "${TempRoot}\child"
$ChildSd = Get-Acl $Child -Audit
$ChildSd.SetAuditRuleProtection($true, $false)
$ChildSd | Set-Acl

# This should fix it, but it doesn't:
Get-ChildItem $TempRoot -Recurse | ForEach-Object {
    $CurrentItem = $_
    $Result = try {
        $SD = Get-Acl $CurrentItem.FullName -Audit -ErrorAction Stop

        if ($SD.AreAuditRulesProtected) {
            $SD.SetAuditRuleProtection($false, $false)

            $SD | Set-Acl

            'SACL inheritance was disabled; enabled now'
        else {
            'SACL inheritance already enabled'
    catch {
        "Error: ${_}"
    [PSCustomObject] @{
        Path = $CurrentItem.FullName
        Result = $Result

I think it’s a .NET instead of PowerShell issue, though, because the SetAccessControl() method that Get-Item would return won’t fix it, either. If I get a little more time, I may try to see what’s going on under the covers. I’m guessing it has to do with the SACL being null in the underlying CommonSecurityDescriptor instance, but it still ignores it if you create one using SetSecurityDescriptorSddlForm().