简体   繁体   中英

PowerShell / C# SetAuditRuleProtection() Not Working On Some Folders

I've been battling with this for a while now and can't find an explanation. I'm attempting to enable inheritance on a directory for audit rules. In this example, I'm setting the audit rule on c:\\Program Files\\Microsoft SQL Server\\MSSQL12.NEWINSTANCE and propagating to all children. The directory c:\\Program Files\\Microsoft SQL Server\\MSSQL12.NEWINSTANCE\\MSSQL\\Backup gets the audit rule via inheritance, but the Logs directory does not. Here's a snippet of the code I'm using to enable inheritance:

$Path = "C:\Program Files\Microsoft SQL Server\MSSQL12.NEWINSTANCE\MSSQL\Log"

[System.IO.DirectoryInfo]$Info = New-Object -TypeName System.IO.DirectoryInfo($Path)

[System.Security.AccessControl.DirectorySecurity]$Acl = $Info.GetAccessControl()

$Acl.SetAuditRuleProtection($false, $false)

$Info.SetAccessControl($Acl)

I've tried a number of combinations including Get-Acl , Set-Acl , (Get-Item -Path $Path).GetAccessControl() , etc. It appears I can disable inheritance and remove the rules, but not disable inheritance and preserve the existing rules (via modifying the parameters for SetAuditRuleProtection ).

All of this works if I do it via the GUI, so I don't believe it's some issue with the directory or my permissions. Any ideas/thoughts would be welcome.

The trick for me was that you can't do this on a folder or file that does not currently have an SACL (System Access Control List, otherwise known as Audit Rule). I wrote a function that sets the rule on the parent, then recursively iterates through all the children to set the rule, ensuring its being inherited, then removing the extra rule.

<#
.SYNOPSIS
 Sets auditing on the file or folder.

.DESCRIPTION
 Implements a File System Audit Rule on the file or folder.

.PARAMETER Path (Required)
 Specifies the file or folder on which to apply the audit rule.

.PARAMETER Principal (Required)
 Specifies the NTAccount name.

.PARAMETER Success (Optional, Required if "Failure" not present)
 Specifies to implement an audit rule for successes.

.PARAMETER Failure (Optional, Required if "Success" not present)
 Specifies to implement an audit rule for failures.

.PARAMETER Flags (Required)
 This is an array of two integers that indicate what to apply the audit rule to and what type of recursion should be used.

 Inheritance, Propagation:
 This folder only = 0,0
 This folder, subfolders and files = 3,0
 This folder and subfolders = 1,0
 This folder and files = 2,0
 Subfolders and files only = 3,2
 Subfolders only = 1,2
 Files only = 2,3

.EXAMPLE
 Set-Auditing
#>
function Set-Auditing {
  [CmdletBinding(SupportsShouldProcess=$true)]
  Param([Parameter(Mandatory=$true, ValueFromPipeline=$false)] [ValidateNotNullOrEmpty()] [string]$Path,
        [Parameter(Mandatory=$true, ValueFromPipeline=$false)] [ValidateNotNullOrEmpty()] [string]$Principal,
        [Parameter(Mandatory=$true, ValueFromPipeline=$false)] [ValidateSet("AppendData","ChangePermissions","CreateDirectories","CreateFiles","Delete","DeleteSubdirectoriesAndFiles","ExecuteFile","FullControl","ListDirectory","Modify","Read","ReadAndExecute","ReadAttributes","ReadData","ReadExtendedAttributes","ReadPermissions","Synchronize","TakeOwnership","Traverse","Write","WriteAttributes","WriteData","WriteExtendedAttributes")] [string[]]$Rights,
        [Parameter(Mandatory=$true, ValueFromPipeline=$false, ParameterSetName="Both")]
        [Parameter(Mandatory=$true, ValueFromPipeline=$false, ParameterSetName="Success")] [switch]$Success,
        [Parameter(Mandatory=$true, ValueFromPipeline=$false, ParameterSetName="Both")]
        [Parameter(Mandatory=$true, ValueFromPipeline=$false, ParameterSetName="Failure")] [switch]$Failure,
        [Parameter(Mandatory=$true, ValueFromPipeline=$false)] [int[]]$Flags)

  Begin {
    # Determine if audit rule exists
    if ($Success.IsPresent) { $AuditFlags=1 } else { $AuditFlags=0 }
    if ($Failure.IsPresent) { $AuditFlags+=2 }

    # Inheritance Flags
    # This folder only = 0
    # This folder, subfolders and files = 3
    # This folder and subfolders = 1
    # This folder and files = 2
    # Subfolders and files only = 3
    # Subfolders only = 1
    # Files only = 2

    # Propagation Flags
    # This folder only = 0
    # This folder, subfolders and files = 0
    # This folder and subfolders = 0
    # This folder and files = 0
    # Subfolders and files only = 2
    # Subfolders only = 2
    # Files only = 2

    # File System Rights
    $fsrAppendData                  =0x000004
    $fsrChangePermissions           =0x040000
    $fsrCreateDirectories           =0x000004
    $fsrCreateFiles                 =0x000002
    $fsrDelete                      =0x010000
    $fsrDeleteSubdirectoriesAndFiles=0x000040
    $fsrExecuteFile                 =0x000020
    $fsrFullControl                 =0x1F01FF
    $fsrListDirectory               =0x000001
    $fsrModify                      =0x0301BF
    $fsrRead                        =0x020089
    $fsrReadAndExecute              =0x0200A9
    $fsrReadAttributes              =0x000080
    $fsrReadData                    =0x000001
    $fsrReadExtendedAttributes      =0x000008
    $fsrReadPermissions             =0x020000
    $fsrSynchronize                 =0x100000
    $fsrTakeOwnership               =0x080000 
    $fsrTraverse                    =0x000020
    $fsrWrite                       =0x000116
    $fsrWriteAttributes             =0x000100
    $fsrWriteData                   =0x000002
    $fsrWriteExtendedAttributes     =0x000010

    $RightValues=0
    for ($i=0; $i -lt $Rights.Count; $i++) {
     switch ($Rights[$i]) {
       "AppendData"                   { $RightValues=$RightValues -bor $fsrAppendData }
       "ChangePermissions"            { $RightValues=$RightValues -bor $fsrChangePermissions }
       "CreateDirectories"            { $RightValues=$RightValues -bor $fsrCreateDirectories }
       "CreateFiles"                  { $RightValues=$RightValues -bor $fsrCreateFiles }
       "Delete"                       { $RightValues=$RightValues -bor $fsrDelete }
       "DeleteSubdirectoriesAndFiles" { $RightValues=$RightValues -bor $fsrDeleteSubdirectoriesAndFiles }
       "ExecuteFile"                  { $RightValues=$RightValues -bor $fsrExecuteFile }
       "FullControl"                  { $RightValues=$RightValues -bor $fsrFullControl }
       "ListDirectory"                { $RightValues=$RightValues -bor $fsrListDirectory }
       "Modify"                       { $RightValues=$RightValues -bor $fsrModify }
       "Read"                         { $RightValues=$RightValues -bor $fsrRead }
       "ReadAndExecute"               { $RightValues=$RightValues -bor $fsrReadAndExecute }
       "ReadAttributes"               { $RightValues=$RightValues -bor $fsrReadAttributes }
       "ReadData"                     { $RightValues=$RightValues -bor $fsrReadData }
       "ReadExtendedAttributes"       { $RightValues=$RightValues -bor $fsrReadExtendedAttributes }
       "ReadPermissions"              { $RightValues=$RightValues -bor $fsrReadPermissions }
       "Synchronize"                  { $RightValues=$RightValues -bor $fsrSynchronize }
       "TakeOwnership"                { $RightValues=$RightValues -bor $fsrTakeOwnership }
       "Traverse"                     { $RightValues=$RightValues -bor $fsrTraverse }
       "Write"                        { $RightValues=$RightValues -bor $fsrWrite }
       "WriteAttributes"              { $RightValues=$RightValues -bor $fsrWriteAttributes }
       "WriteData"                    { $RightValues=$RightValues -bor $fsrWriteData }
       "WriteExtendedAttributes"      { $RightValues=$RightValues -bor $fsrWriteExtendedAttributes }
     }
    }

    Write-Verbose "Acquiring object $($FS.FullName)"
    $FS=Get-Item -Path $Path
    $ACL=Get-Acl -Path $Path -Audit
    $NothingToDo=$false
    for ($i=0; $i -lt $ACL.Audit.Count; $i++) {
      if ($ACL.Audit[$i].IdentityReference.Value -eq $Principal) {
        if ($ACL.Audit[$i].AuditFlags.value__ -eq $AuditFlags) {
          if ($ACL.Audit[$i].PropagationFlags.value__ -eq $Flags[1]) {
            if ($ACL.Audit[$i].InheritanceFlags.value__ -eq $Flags[0]) {
              if ($ACL.Audit[$i].FileSystemRights.value__ -eq $RightValues) { $NothingToDo=$true; Write-Verbose "Nothing to do" }
            }
          }
        }
      }
    }
  }

  Process {
    if (!$NothingToDo) {
      # There is one case where we will not propagage the rules.  This is when $Flags = 0,0
      if (($Flags[0] -eq 0) -and ($Flags[1] -eq 0)) { Write-Verbose "Flags = 0,0; no propagation necessary." }
      else {
        Write-Verbose "Setting Audit Rule"
        if ($Principal.Contains("\")) { $NTAccount=New-Object System.Security.Principal.NTAccount(($Principal.Split("\"))[0],($Principal.Split("\"))[1]) }
        else { $NTAccount=New-Object System.Security.Principal.NTAccount($Principal) }
        $FSAR=New-Object System.Security.AccessControl.FileSystemAuditRule($NTAccount,$RightValues,$Flags[0],$Flags[1],$AuditFlags)
        $FAR=New-Object System.Security.AccessControl.FileSystemAuditRule($NTAccount,$RightValues,$AuditFlags)
        $ACL.AddAuditRule($FSAR)
        $ACL.SetAuditRuleProtection($false, $true)
        Write-Verbose "Applying rule to $($ACL.Path.Replace('Microsoft.PowerShell.Core\FileSystem::',''))"
        $FS.SetAccessControl($ACL)

        # Now, ensure that all folders and files have inheritance enabled.
        $FS=Get-ChildItem -Path $Path -Recurse
        $FS=@($FS)
        for ($i=0; $i -lt $FS.Count; $i++) {
          Write-Verbose "Acquiring object $($FS[$i].FullName)"
          $ACL=Get-Acl -Path $FS[$i].FullName -Audit
          if (Test-Path $ACL.Path -PathType Leaf) { $ACL.AddAuditRule($FAR) } else { $ACL.AddAuditRule($FSAR) }
          $ACL.SetAuditRuleProtection($false, $true)
          $FS[$i].SetAccessControl($ACL)
          Write-Verbose "Applying rule to $($ACL.Path.Replace('Microsoft.PowerShell.Core\FileSystem::',''))"
          if (Test-Path $ACL.Path -PathType Leaf) { $ACL.RemoveAuditRule($FAR) > $null } else { $ACL.RemoveAuditRule($FSAR) > $null }
          Write-Verbose "Removing extra rule from $($ACL.Path)"
          $FS[$i].SetAccessControl($ACL)
        }
      }
    }
    else { Write-Verbose "Nothing to do." }
  }
}

From what I grasp looking everywhere on the Net you can't reset audit inheritance unless you have an audit rule (it doesn't handle well a $null value). So in your case it should look like:

# Temporary audit rule just to make sure it is not null.  (otherwhise won't work)
$tmpAR= New-Object System.Security.AccessControl.FileSystemAuditRule(
            'Everyone',
    [System.Security.AccessControl.FileSystemRights]::Delete, 
    [System.Security.AccessControl.AuditFlags]::Success
)
$Acl.SetAuditRule($tmpAR)
$Acl.SetAuditRuleProtection($false, $false)
# Don't forget the Set-ACL at the end
Set-ACL -Path $Path -AclObject $Acl

In my case that worked.

Note: I used to get the ACL: $Acl = Get-ACL -Path $Path -Audit

Hopping this help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM