six demon bag

Wind, fire, all that kind of thing!

2014-07-11

Compare ACLs

Recently I had the need to compare the ACLs of two Active Directory objects. With file ACLs I could expand their Access properties and compare the resulting lists with Compare-Object. However, for ACLs of Active Directory objects that didn't work, so I came up with the following function.


function Compare-Acl {
  [CmdletBinding()]
  Param(
    [Parameter()]
    [string]$ReferenceObjectPath,
    [Parameter()]
    [string]$DifferenceObjectPath,
    [Switch]
    [bool]$ExcludeDifferent = $false,
    [Switch]
    [bool]$IncludeEqual = $false
  )

  $acl1 = Get-Acl -Path $ReferenceObjectPath | select -Expand Access
  $acl2 = Get-Acl -Path $DifferenceObjectPath | select -Expand Access

  $props1 = $acl1 | select -First 1 | % { $_.PSObject.Properties | % { $_.Name } }
  $props2 = $acl2 | select -First 1 | % { $_.PSObject.Properties | % { $_.Name } }

  if ( Compare-Object $props1 $props2 ) {
    throw "Objects don't have matching property sets."
  }

  $csv1 = $acl1 | ConvertTo-Csv -NoType
  $csv2 = $acl2 | ConvertTo-Csv -NoType

  $diff1 = $csv1 | ? { $csv2 -notcontains $_ }
  $diff2 = $csv2 | ? { $csv1 -notcontains $_ }

  if ( $diff1 -and -not $ExcludeDifferent ) {
    $diff1 | ConvertFrom-Csv -Header $props1 | % {
      New-Object -Type PSObject -Property @{
        'AccessRule'    = $_
        'SideIndicator' = '<='
      }
    }
  }
  if ( $diff2 -and -not $ExcludeDifferent ) {
    $diff2 | ConvertFrom-Csv -Header $props2 | % {
      New-Object -Type PSObject -Property @{
        'AccessRule'    = $_
        'SideIndicator' = '=>'
      }
    }
  }
  if ( $IncludeEqual ) {
    $csv1 | ? { $csv2 -contains $_ } | ConvertFrom-Csv -Header $props1 | % {
      New-Object -Type PSObject -Property @{
        'AccessRule'    = $_
        'SideIndicator' = '=='
      }
    }
  }
}

Usage example:

PS C:\> Import-Module ActiveDirectory        # otherwise the AD: PSDrive won't work
PS C:\> $dn1 = 'OU=some,DC=example,DC=org'
PS C:\> $dn2 = 'OU=other,DC=example,DC=org'
PS C:\> Compare-Acl -Reference "AD:$dn1" -Difference "AD:$dn2"

AccessRule                                                  SideIndicator
----------                                                  -------------
@{ActiveDirectoryRights=ReadProperty, WriteProperty; Inh... <=
@{ActiveDirectoryRights=ReadProperty, WriteProperty; Inh... <=
@{ActiveDirectoryRights=ReadProperty, WriteProperty; Inh... <=
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... <=
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... <=
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... <=
@{ActiveDirectoryRights=ExtendedRight; InheritanceType=D... <=
@{ActiveDirectoryRights=ExtendedRight; InheritanceType=D... <=
@{ActiveDirectoryRights=ReadProperty, WriteProperty; Inh... <=
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... <=
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... <=
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... <=
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... <=
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... <=
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... <=
@{ActiveDirectoryRights=Self; InheritanceType=Descendent... <=
@{ActiveDirectoryRights=ReadProperty, WriteProperty; Inh... <=
@{ActiveDirectoryRights=ReadProperty, WriteProperty; Inh... <=
@{ActiveDirectoryRights=ReadProperty, WriteProperty; Inh... <=
@{ActiveDirectoryRights=ReadProperty, WriteProperty; Inh... <=
@{ActiveDirectoryRights=GenericAll; InheritanceType=Desc... =>
@{ActiveDirectoryRights=GenericAll; InheritanceType=Desc... =>
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... =>
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... =>

PS C:\> Compare-Acl -Reference "AD:$dn1" -Difference "AD:$dn2" -Include -Exclude

AccessRule                                                  SideIndicator
----------                                                  -------------
@{ActiveDirectoryRights=ActiveDirectoryRights; Inheritan... ==
@{ActiveDirectoryRights=DeleteChild, DeleteTree, Delete;... ==
@{ActiveDirectoryRights=GenericRead; InheritanceType=Non... ==
@{ActiveDirectoryRights=GenericRead; InheritanceType=Non... ==
@{ActiveDirectoryRights=GenericAll; InheritanceType=None... ==
@{ActiveDirectoryRights=GenericAll; InheritanceType=None... ==
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... ==
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... ==
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... ==
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... ==
@{ActiveDirectoryRights=CreateChild, DeleteChild; Inheri... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=ReadProperty; InheritanceType=De... ==
@{ActiveDirectoryRights=WriteProperty; InheritanceType=D... ==
@{ActiveDirectoryRights=GenericRead; InheritanceType=Des... ==
@{ActiveDirectoryRights=GenericRead; InheritanceType=Des... ==
@{ActiveDirectoryRights=GenericRead; InheritanceType=Des... ==
@{ActiveDirectoryRights=ReadProperty, WriteProperty; Inh... ==
@{ActiveDirectoryRights=ReadProperty, WriteProperty, Ext... ==
@{ActiveDirectoryRights=GenericAll; InheritanceType=All;... ==
@{ActiveDirectoryRights=ListChildren; InheritanceType=Al... ==
@{ActiveDirectoryRights=CreateChild, Self, WriteProperty... ==

PS C:\> Compare-Acl -Reference 'C:\Windows' -Difference "AD:$dn2"
Objects don't have matching property sets.
At line:18 char:5
+     throw "Objects don't have matching property sets."
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Objects don't h... property sets.:String) [],
                              RuntimeException
    + FullyQualifiedErrorId : Objects don't have matching property sets.

PS C:\> Compare-Acl -Reference 'C:\Windows' -Difference 'C:\bootmgr'

AccessRule                                                  SideIndicator
----------                                                  -------------
@{FileSystemRights=268435456; AccessControlType=Allow; I... <=
@{FileSystemRights=268435456; AccessControlType=Allow; I... <=
@{FileSystemRights=Modify, Synchronize; AccessControlTyp... <=
@{FileSystemRights=268435456; AccessControlType=Allow; I... <=
@{FileSystemRights=Modify, Synchronize; AccessControlTyp... <=
@{FileSystemRights=-1610612736; AccessControlType=Allow;... <=
@{FileSystemRights=268435456; AccessControlType=Allow; I... <=
@{FileSystemRights=ReadAndExecute, Synchronize; AccessCo... <=
@{FileSystemRights=-1610612736; AccessControlType=Allow;... <=
@{FileSystemRights=ReadAndExecute, Synchronize; AccessCo... =>
@{FileSystemRights=ReadAndExecute, Synchronize; AccessCo... =>

PS C:\> Compare-Acl -Reference 'HKLM:\SOFTWARE' -Difference 'HKCU:\Software'

AccessRule                                                  SideIndicator
----------                                                  -------------
@{RegistryRights=268435456; AccessControlType=Allow; Ide... <=
@{RegistryRights=268435456; AccessControlType=Allow; Ide... <=
@{RegistryRights=FullControl; AccessControlType=Allow; I... <=
@{RegistryRights=268435456; AccessControlType=Allow; Ide... <=
@{RegistryRights=FullControl; AccessControlType=Allow; I... <=
@{RegistryRights=-2147483648; AccessControlType=Allow; I... <=
@{RegistryRights=ReadKey; AccessControlType=Allow; Ident... <=
@{RegistryRights=FullControl; AccessControlType=Allow; I... =>
@{RegistryRights=FullControl; AccessControlType=Allow; I... =>
@{RegistryRights=FullControl; AccessControlType=Allow; I... =>
@{RegistryRights=ReadKey; AccessControlType=Allow; Ident... =>

Posted 18:50 [permalink]