From 01e0744531299808da4b67cb9dfa53a94187bf65 Mon Sep 17 00:00:00 2001 From: Reggie Gibson Date: Tue, 16 Jan 2018 17:17:40 -0500 Subject: [PATCH 1/6] initial ActiveDirectoryAccessEntry resource --- .../ActiveDirectoryAccessEntry.psm1 | 539 ++++++++++++++++++ .../ActiveDirectoryAccessEntry.schema.mof | 25 + 2 files changed, 564 insertions(+) create mode 100644 DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 create mode 100644 DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.schema.mof diff --git a/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 b/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 new file mode 100644 index 0000000..7362ed5 --- /dev/null +++ b/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 @@ -0,0 +1,539 @@ +Import-Module -Name (Join-Path -Path ( Split-Path $PSScriptRoot -Parent ) ` + -ChildPath 'AccessControlResourceHelper\AccessControlResourceHelper.psm1') ` + -Force + +# Localized messages +data LocalizedData +{ + # culture="en-US" + ConvertFrom-StringData -StringData @' + ErrorPathNotFound = The requested path "{0}" cannot be found. + AclNotFound = Error obtaining "{0}" ACL + AclFound = Obtained "{0}" ACL + RemoveAccessError = "Unable to remove Access for "{0}" +'@ +} + +Function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([Hashtable])] + param + ( + [Parameter(Mandatory=$true)] + [System.String] + $DistinguishedName, + + [Parameter(Mandatory=$true)] + [Microsoft.Management.Infrastructure.CimInstance[]] + $AccessControlList + ) + + Assert-Module -ModuleName 'ActiveDirectory' + Import-Module -Name 'ActiveDirectory' -Verbose:$false + + $namespace = "root/Microsoft/Windows/DesiredStateConfiguration" + $cimAccessControlList = New-Object -TypeName 'System.Collections.ObjectModel.Collection`1[Microsoft.Management.Infrastructure.CimInstance]' + + $path = Join-Path -Path "ad:\" -ChildPath $DistinguishedName + + if(Test-Path -Path $path) + { + $currentAcl = Get-Acl -Path $path -ErrorAction Stop + + if($null -ne $currentAcl) + { + $message = $LocalizedData.AclFound -f $path + Write-Verbose -Message $message + + foreach($principal in $AccessControlList) + { + $cimAccessControlEntry = New-Object -TypeName 'System.Collections.ObjectModel.Collection`1[Microsoft.Management.Infrastructure.CimInstance]' + + $principalName = $principal.Principal + $ForcePrincipal = $principal.ForcePrincipal + + $identity = Resolve-Identity -Identity $principalName + $currentPrincipalAccess = $currentAcl.Access.Where({$_.IdentityReference -eq $identity.Name}) + + foreach($Access in $currentPrincipalAccess) + { + $ActiveDirectoryRights = $Access.ActiveDirectoryRights.ToString().Split(',').Trim() + $InheritanceType = $Access.InheritanceType.ToString() + $inheritedObjectType = $Access.InheritedObjectType.ToString() + + $cimAccessControlEntry += New-CimInstance -ClientOnly -Namespace $namespace -ClassName ActiveDirectoryAccessRule -Property @{ + ActiveDirectoryRights = @($ActiveDirectoryRights) + InheritanceType = $InheritanceType + InheritedObjectType = $inheritedObjectType + Ensure = "" + } + } + + $CimAccessControlList += New-CimInstance -ClientOnly -Namespace $namespace -ClassName ActiveDirectorySystemAccessControlList -Property @{ + Principal = $principalName + ForcePrincipal = $ForcePrincipal + AccessControlEntry = [Microsoft.Management.Infrastructure.CimInstance[]]@($cimAccessControlEntry) + } + } + } + else + { + $message = $LocalizedData.AclNotFound -f $path + Write-Verbose -Message $message + } + } + else + { + $Message = $LocalizedData.ErrorPathNotFound -f $path + Write-Verbose -Message $Message + } + + $ReturnValue = @{ + Force = $Force + DistinguishedName = $DistinguishedName + AccessControlList = $CimAccessControlList + } + + return $ReturnValue +} + +Function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory=$true)] + [System.String] + $DistinguishedName, + + [Parameter(Mandatory=$true)] + [Microsoft.Management.Infrastructure.CimInstance[]] + $AccessControlList + ) + + Assert-Module -ModuleName 'ActiveDirectory' + Import-Module -Name 'ActiveDirectory' -Verbose:$false + + $path = Join-Path -Path "ad:\" -ChildPath $DistinguishedName + + if(Test-Path -Path $path) + { + $currentAcl = Get-Acl -Path $path + if($null -ne $currentAcl) + { + if($Force) + { + foreach($accessControlItem in $AccessControlList) + { + $principal = $accessControlItem.Principal + $identity = Resolve-Identity -Identity $principal + $identityRef = New-Object System.Security.Principal.NTAccount($identity.Name) + + $aclRules += ConvertTo-ActiveDirectoryAccessRule -AccessControlList $accessControlItem -IdentityRef $identityRef + } + + $actualAce = $currentAcl.Access + + $results = Compare-ActiveDirectoryAccessRule -Expected $aclRules -Actual $actualAce + + $expected = $results.Rules + $absentToBeRemoved = $results.Absent + $toBeRemoved = $results.ToBeRemoved + } + else + { + foreach($accessControlItem in $AccessControlList) + { + $principal = $accessControlItem.Principal + $identity = Resolve-Identity -Identity $principal + $identityRef = New-Object System.Security.Principal.NTAccount($identity.Name) + + $actualAce = $currentAcl.Access.Where({$_.IdentityReference -eq $identity.Name}) + + $aclRules = ConvertTo-ActiveDirectoryAccessRule -AccessControlList $accessControlItem -IdentityRef $identityRef + $results = Compare-ActiveDirectoryAccessRule -Expected $aclRules -Actual $actualAce + + $expected += $results.Rules + $absentToBeRemoved += $results.Absent + + if($accessControlItem.ForcePrinciPal) + { + $toBeRemoved += $results.ToBeRemoved + } + } + } + + $isInherited = 0 + $isInherited += $absentToBeRemoved.Rule.Where({$_.IsInherited -eq $true}).Count + $isInherited += $toBeRemoved.Rule.Where({$_.IsInherited -eq $true}).Count + + if($isInherited -gt 0) + { + $currentAcl.SetAccessRuleProtection($true,$true) + Set-Acl -Path $path -AclObject $currentAcl + } + + foreach($rule in $expected) + { + if($rule.Match -eq $false) + { + $nonMatch = $rule.Rule + ("Adding Access rule:"), + ("> Path : '{0}'" -f $path), + ("> IdentityReference : '{0}'" -f $nonMatch.IdentityReference), + ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), + ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), + ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)) | + Write-Verbose + + $currentAcl.AddAccessRule($rule.Rule) + } + } + + foreach($rule in $absentToBeRemoved.Rule) + { + $nonMatch = $rule.Rule + ("Removing Access rule:"), + ("> Path : '{0}'" -f $path), + ("> IdentityReference : '{0}'" -f $nonMatch.IdentityReference), + ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), + ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), + ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)) | + Write-Verbose + + $currentAcl.RemoveAccessRule($rule) + } + + foreach($rule in $toBeRemoved.Rule) + { + $nonMatch = $rule.Rule + ("Removing Access rule:"), + ("> Path : '{0}'" -f $path), + ("> IdentityReference : '{0}'" -f $nonMatch.IdentityReference), + ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), + ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), + ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)) | + Write-Verbose + $currentAcl.RemoveAccessRule($rule) + } + + Set-Acl -Path $path -AclObject $currentAcl + } + else + { + $message = $LocalizedData.AclNotFound -f $path + Write-Verbose -Message $message + } + } + else + { + $Message = $LocalizedData.ErrorPathNotFound -f $path + Write-Verbose -Message $Message + } +} + +Function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory=$true)] + [System.String] + $DistinguishedName, + + [Parameter(Mandatory=$true)] + [Microsoft.Management.Infrastructure.CimInstance[]] + $AccessControlList + ) + + Assert-Module -ModuleName 'ActiveDirectory' + Import-Module -Name 'ActiveDirectory' -Verbose:$false + + $inDesiredState = $True + $path = Join-Path -Path "ad:\" -ChildPath $DistinguishedName + + if(Test-Path -Path $path) + { + $currentAcl = Get-Acl -Path $path + + if($null -ne $currentAcl) + { + if($Force) + { + foreach($accessControlItem in $AccessControlList) + { + $principal = $accessControlItem.Principal + $identity = Resolve-Identity -Identity $principal + $identityRef = New-Object System.Security.Principal.NTAccount($identity.Name) + + $aclRules += ConvertTo-ActiveDirectoryAccessRule -AccessControlList $accessControlItem -IdentityRef $identityRef + } + + $actualAce = $currentAcl.Access + + $results = Compare-ActiveDirectoryAccessRule -Expected $aclRules -Actual $actualAce + + $expected = $results.Rules + $absentToBeRemoved = $results.Absent + $toBeRemoved = $results.ToBeRemoved + } + else + { + foreach($accessControlItem in $AccessControlList) + { + $principal = $accessControlItem.Principal + $identity = Resolve-Identity -Identity $principal + $identityRef = New-Object System.Security.Principal.NTAccount($identity.Name) + + $aclRules = ConvertTo-ActiveDirectoryAccessRule -AccessControlList $accessControlItem -IdentityRef $identityRef + + $actualAce = $currentAcl.Access.Where({$_.IdentityReference -eq $identity.Name}) + + $results = Compare-ActiveDirectoryAccessRule -Expected $aclRules -Actual $actualAce + + $expected += $results.Rules + $absentToBeRemoved += $results.Absent + + if($accessControlItem.ForcePrincipal) + { + $toBeRemoved += $results.ToBeRemoved + } + + } + } + + foreach($rule in $expected) + { + if($rule.Match -eq $false) + { + $nonMatch = $rule.Rule + ("Found missing [present] Access rule:"), + ("> Principal : '{0}'" -f $principal), + ("> Path : '{0}'" -f $path), + ("> IdentityReference : '{0}'" -f $nonMatch.IdentityReference), + ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), + ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), + ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)) | + Write-Verbose + + $inDesiredState = $False + } + } + + if($absentToBeRemoved.Count -gt 0) + { + $nonMatch = $rule.Rule + ("Found [absent] Access rule:"), + ("> Principal : '{0}'" -f $principal), + ("> Path : '{0}'" -f $path), + ("> IdentityReference : '{0}'" -f $nonMatch.IdentityReference), + ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), + ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), + ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType))| + Write-Verbose + + $inDesiredState = $False + } + + if($toBeRemoved.Count -gt 0) + { + $nonMatch = $rule.Rule + ("Non-matching Access rule found:"), + ("> Principal : '{0}'" -f $principal), + ("> Path : '{0}'" -f $path), + ("> IdentityReference : '{0}'" -f $nonMatch.IdentityReference), + ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), + ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), + ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)) | + Write-Verbose + $inDesiredState = $False + } + } + else + { + $message = $LocalizedData.AclNotFound -f $path + Write-Verbose -Message $message + $inDesiredState = $False + } + } + else + { + $message = $LocalizedData.ErrorPathNotFound -f $path + Write-Verbose -Message $Message + $inDesiredState = $False + } + + return $inDesiredState +} + +Function ConvertTo-ActiveDirectoryAccessRule +{ + param + ( + [Parameter(Mandatory = $true)] + [Microsoft.Management.Infrastructure.CimInstance] + $AccessControlList, + + [Parameter(Mandatory = $true)] + [System.Security.Principal.NTAccount] + $IdentityRef + ) + + $referenceObject = @() + + foreach($ace in $AccessControlList.AccessControlEntry) + { + $inheritedObjectType = Get-SchemaIdGuid -ObjectName $ace.InheritedObjectType + $rule = [PSCustomObject]@{ + Rules = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($IdentityRef, $ace.ActiveDirectoryRights, $ace.AccessControlType, $ace.InheritanceType, $inheritedObjectType) + Ensure = $ace.Ensure + } + $referenceObject += $rule + } + + return $referenceObject +} + +Function Compare-ActiveDirectoryAccessRule +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCustomObject[]] + $Expected, + + [Parameter()] + [System.DirectoryServices.ActiveDirectoryAccessRule[]] + $Actual + ) + + $results = @() + $toBeRemoved = @() + $absentToBeRemoved = @() + + $presentRules = $Expected.Where({$_.Ensure -eq 'Present'}).Rules + $absentRules = $Expected.Where({$_.Ensure -eq 'Absent'}).Rules + foreach($referenceObject in $presentRules) + { + $match = $Actual.Where({ + $_.ActiveDirectoryRights -eq $referenceObject.ActiveDirectoryRights -and + $_.AccessControlType -eq $referenceObject.AccessControlType -and + $_.InheritanceType -eq $referenceObject.InheritanceType -and + $_.InheritedObjectType -eq $referenceObject.InheritedObjectType -and + $_.IdentityReference -eq $referenceObject.IdentityReference + }) + if($match.Count -ge 1) + { + $results += [PSCustomObject]@{ + Rule = $referenceObject + Match = $true + } + } + else + { + $results += [PSCustomObject]@{ + Rule = $referenceObject + Match = $false + } + } + } + + foreach($referenceObject in $absentRules) + { + $match = $Actual.Where({ + $_.ActiveDirectoryRights -eq $referenceObject.ActiveDirectoryRights -and + $_.AccessControlType -eq $referenceObject.AccessControlType -and + $_.InheritanceType -eq $referenceObject.InheritanceType -and + $_.InheritedObjectType -eq $referenceObject.InheritedObjectType -and + $_.IdentityReference -eq $referenceObject.IdentityReference + }) + if($match.Count -gt 0) + { + $absentToBeRemoved += [PSCustomObject]@{ + Rule = $referenceObject + } + } + } + + foreach($referenceObject in $Actual) + { + $match = $Expected.Rules.Where({ + $_.ActiveDirectoryRights -eq $referenceObject.ActiveDirectoryRights -and + $_.AccessControlType -eq $referenceObject.AccessControlType -and + $_.InheritanceType -eq $referenceObject.InheritanceType -and + $_.InheritedObjectType -eq $referenceObject.InheritedObjectType -and + $_.IdentityReference -eq $referenceObject.IdentityReference + }) + if($match.Count -eq 0) + { + $toBeRemoved += [PSCustomObject]@{ + Rule = $referenceObject + } + } + } + + return [PSCustomObject]@{ + Rules = $results + ToBeRemoved = $toBeRemoved + Absent = $absentToBeRemoved + } +} + +function Assert-Module +{ + [CmdletBinding()] + param + ( + [Parameter()] [ValidateNotNullOrEmpty()] + [System.String] + $ModuleName = 'ActiveDirectory' + ) + + if (-not (Get-Module -Name $ModuleName -ListAvailable)) + { + $errorId = '{0}_ModuleNotFound' -f $ModuleName; + $errorMessage = $localizedString.RoleNotFoundError -f $ModuleName; + ThrowInvalidOperationError -ErrorId $errorId -ErrorMessage $errorMessage; + } +} + +Function Get-SchemaIdGuid +{ + Param + ( + [Parameter()] + [string] + $ObjectName + ) + + if($ObjectName) + { + $value = Get-ADObject -filter {name -eq $ObjectName} -SearchBase (Get-ADRootDSE).schemaNamingContext -prop schemaIDGUID + return [system.guid]$value.schemaIDGUID + } + else + { + return [system.guid]"00000000-0000-0000-0000-000000000000" + } +} + +Function Get-SchemaObjectName +{ + Param + ( + [Parameter()] + [guid] + $SchemaIdGuid + ) + + $value = Get-ADObject -filter {schemaIDGUID -eq $SchemaIdGuid} -SearchBase (Get-ADRootDSE).schemaNamingContext -prop schemaIDGUID + return $value.name +} diff --git a/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.schema.mof b/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.schema.mof new file mode 100644 index 0000000..1bed3db --- /dev/null +++ b/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.schema.mof @@ -0,0 +1,25 @@ +[ClassVersion("1.0.0.0")] +class ActiveDirectoryAccessRule +{ + [Required, Description("Indicates whether to allow or deny access to the target item."), ValueMap{"Allow","Deny"}, Values{"Allow","Deny"}] String AccessControlType; + [Required, Description("Specifies the access rights that are assigned to an Active Directory Domain Services object."), ValueMap{"AccessSystemSecurity","CreateChild","Delete","DeleteChild","DeleteTree","ExtendedRight","GenericAll","GenericExecute","GenericRead","GenericWrite","ListChildren","ListObject","ReadControl","ReadProperty","Self","WriteDacl","WriteOwner","WriteProperty"}, Values{"AccessSystemSecurity","CreateAllChildObjects","Delete","DeleteAllChildObjects","DeleteSubtree","AllExtendedRights","FullControl","Execute","Read","Write","ListContents","ListObject","ReadPermissions","ReadAllProperties","AllValidatedWrites","ModifyPermissions","ModifyOwner","WriteAllProperties"}] String ActiveDirectoryRights[]; + [Write, Description("Specifies if, and how, ACE information is applied to an object and its descendents."), ValueMap{"1","4","2","0","3"}, Values{"All","Children","Descendents","None","SelfAndChildren"}] String InheritanceType; + [Write, Description("Specifies the schema GUID of the object to which the access rule applies.")] String ObjectType; + [Write, Description("Specifies the object type name that identifies the type of child object that can inherit this access rule.")] String InheritedObjectType; + [Required, ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] String Ensure; +}; + +[ClassVersion("1.0.0.0")] +class ActiveDirectoryAccessControlList +{ + [Write, Description("Indicates the identity of the principal.")] String Principal; + [Write] Boolean ForcePrincipal; + [Write, Description("Indicates the access control entry in the form of an array of instances of the AccessControlList CIM class."), EmbeddedInstance("ActiveDirectoryAccessRule")] String AccessControlEntry[]; +}; + +[ClassVersion("1.0.0.0"), FriendlyName("ActiveDirectoryAccessEntry")] +class ActiveDirectoryAccessEntry : OMI_BaseResource +{ + [Key, Description("Indicates the Distinguished Name value for the target Active Directory Object.")] String DistinguishedName; + [Required, Description("Indicates the access control information in the form of an array of instances of the ActiveDirectoryAuditRuleList CIM class."), EmbeddedInstance("ActiveDirectoryAccessControlList")] String AccessControlList[]; +}; From be76b78302c5717f524c0d4eb7daf91389190ea7 Mon Sep 17 00:00:00 2001 From: Reggie Gibson Date: Thu, 18 Jan 2018 11:46:01 -0500 Subject: [PATCH 2/6] updates to ActiveDirectoryAccessEntry resource --- .../ActiveDirectoryAccessEntry.psm1 | 100 ++++++++---------- 1 file changed, 45 insertions(+), 55 deletions(-) diff --git a/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 b/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 index 7362ed5..31864ce 100644 --- a/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 +++ b/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 @@ -51,28 +51,32 @@ Function Get-TargetResource $cimAccessControlEntry = New-Object -TypeName 'System.Collections.ObjectModel.Collection`1[Microsoft.Management.Infrastructure.CimInstance]' $principalName = $principal.Principal - $ForcePrincipal = $principal.ForcePrincipal + $forcePrincipal = $principal.ForcePrincipal $identity = Resolve-Identity -Identity $principalName $currentPrincipalAccess = $currentAcl.Access.Where({$_.IdentityReference -eq $identity.Name}) - foreach($Access in $currentPrincipalAccess) + foreach($access in $currentPrincipalAccess) { - $ActiveDirectoryRights = $Access.ActiveDirectoryRights.ToString().Split(',').Trim() - $InheritanceType = $Access.InheritanceType.ToString() - $inheritedObjectType = $Access.InheritedObjectType.ToString() + $accessControlType = $access.AccessControlType.ToString() + $activeDirectoryRights = $access.ActiveDirectoryRights.ToString().Split(',').Trim() + $inheritanceType = $access.InheritanceType.ToString() + $inheritedObjectType = $access.InheritedObjectType.ToString() + $objectType = $access.ObjectType.ToString() $cimAccessControlEntry += New-CimInstance -ClientOnly -Namespace $namespace -ClassName ActiveDirectoryAccessRule -Property @{ - ActiveDirectoryRights = @($ActiveDirectoryRights) - InheritanceType = $InheritanceType + AccessControlType = $accessControlType + ActiveDirectoryRights = @($activeDirectoryRights) + InheritanceType = $inheritanceType InheritedObjectType = $inheritedObjectType + ObjectType = $objectType Ensure = "" } } - $CimAccessControlList += New-CimInstance -ClientOnly -Namespace $namespace -ClassName ActiveDirectorySystemAccessControlList -Property @{ + $CimAccessControlList += New-CimInstance -ClientOnly -Namespace $namespace -ClassName ActiveDirectoryAccessControlList -Property @{ Principal = $principalName - ForcePrincipal = $ForcePrincipal + ForcePrincipal = $forcePrincipal AccessControlEntry = [Microsoft.Management.Infrastructure.CimInstance[]]@($cimAccessControlEntry) } } @@ -90,7 +94,6 @@ Function Get-TargetResource } $ReturnValue = @{ - Force = $Force DistinguishedName = $DistinguishedName AccessControlList = $CimAccessControlList } @@ -185,7 +188,8 @@ Function Set-TargetResource ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), - ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)) | + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), + ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | Write-Verbose $currentAcl.AddAccessRule($rule.Rule) @@ -201,8 +205,9 @@ Function Set-TargetResource ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), - ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)) | - Write-Verbose + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), + ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | + Write-Verbose $currentAcl.RemoveAccessRule($rule) } @@ -216,8 +221,9 @@ Function Set-TargetResource ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), - ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)) | - Write-Verbose + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), + ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | + Write-Verbose $currentAcl.RemoveAccessRule($rule) } @@ -263,48 +269,26 @@ Function Test-TargetResource if($null -ne $currentAcl) { - if($Force) - { - foreach($accessControlItem in $AccessControlList) - { - $principal = $accessControlItem.Principal - $identity = Resolve-Identity -Identity $principal - $identityRef = New-Object System.Security.Principal.NTAccount($identity.Name) - - $aclRules += ConvertTo-ActiveDirectoryAccessRule -AccessControlList $accessControlItem -IdentityRef $identityRef - } - - $actualAce = $currentAcl.Access - - $results = Compare-ActiveDirectoryAccessRule -Expected $aclRules -Actual $actualAce - - $expected = $results.Rules - $absentToBeRemoved = $results.Absent - $toBeRemoved = $results.ToBeRemoved - } - else + foreach($accessControlItem in $AccessControlList) { - foreach($accessControlItem in $AccessControlList) - { - $principal = $accessControlItem.Principal - $identity = Resolve-Identity -Identity $principal - $identityRef = New-Object System.Security.Principal.NTAccount($identity.Name) + $principal = $accessControlItem.Principal + $identity = Resolve-Identity -Identity $principal + $identityRef = New-Object System.Security.Principal.NTAccount($identity.Name) - $aclRules = ConvertTo-ActiveDirectoryAccessRule -AccessControlList $accessControlItem -IdentityRef $identityRef - - $actualAce = $currentAcl.Access.Where({$_.IdentityReference -eq $identity.Name}) + $aclRules = ConvertTo-ActiveDirectoryAccessRule -AccessControlList $accessControlItem -IdentityRef $identityRef - $results = Compare-ActiveDirectoryAccessRule -Expected $aclRules -Actual $actualAce + $actualAce = $currentAcl.Access.Where({$_.IdentityReference -eq $identity.Name}) - $expected += $results.Rules - $absentToBeRemoved += $results.Absent + $results = Compare-ActiveDirectoryAccessRule -Expected $aclRules -Actual $actualAce - if($accessControlItem.ForcePrincipal) - { - $toBeRemoved += $results.ToBeRemoved - } + $expected += $results.Rules + $absentToBeRemoved += $results.Absent + if($accessControlItem.ForcePrincipal) + { + $toBeRemoved += $results.ToBeRemoved } + } foreach($rule in $expected) @@ -319,7 +303,8 @@ Function Test-TargetResource ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), - ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)) | + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), + ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | Write-Verbose $inDesiredState = $False @@ -336,9 +321,9 @@ Function Test-TargetResource ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), - ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType))| + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), + ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | Write-Verbose - $inDesiredState = $False } @@ -352,7 +337,8 @@ Function Test-TargetResource ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), - ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)) | + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), + ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | Write-Verbose $inDesiredState = $False } @@ -392,8 +378,9 @@ Function ConvertTo-ActiveDirectoryAccessRule foreach($ace in $AccessControlList.AccessControlEntry) { $inheritedObjectType = Get-SchemaIdGuid -ObjectName $ace.InheritedObjectType + $objectType = Get-SchemaIdGuid -ObjectName $ace.ObjectType $rule = [PSCustomObject]@{ - Rules = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($IdentityRef, $ace.ActiveDirectoryRights, $ace.AccessControlType, $ace.InheritanceType, $inheritedObjectType) + Rules = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($IdentityRef, $ace.ActiveDirectoryRights, $ace.AccessControlType, $objectType, $ace.InheritanceType, $inheritedObjectType) Ensure = $ace.Ensure } $referenceObject += $rule @@ -428,6 +415,7 @@ Function Compare-ActiveDirectoryAccessRule $_.AccessControlType -eq $referenceObject.AccessControlType -and $_.InheritanceType -eq $referenceObject.InheritanceType -and $_.InheritedObjectType -eq $referenceObject.InheritedObjectType -and + $_.ObjectType -eq $referenceObject.ObjectType -and $_.IdentityReference -eq $referenceObject.IdentityReference }) if($match.Count -ge 1) @@ -453,6 +441,7 @@ Function Compare-ActiveDirectoryAccessRule $_.AccessControlType -eq $referenceObject.AccessControlType -and $_.InheritanceType -eq $referenceObject.InheritanceType -and $_.InheritedObjectType -eq $referenceObject.InheritedObjectType -and + $_.ObjectType -eq $referenceObject.ObjectType -and $_.IdentityReference -eq $referenceObject.IdentityReference }) if($match.Count -gt 0) @@ -470,6 +459,7 @@ Function Compare-ActiveDirectoryAccessRule $_.AccessControlType -eq $referenceObject.AccessControlType -and $_.InheritanceType -eq $referenceObject.InheritanceType -and $_.InheritedObjectType -eq $referenceObject.InheritedObjectType -and + $_.ObjectType -eq $referenceObject.ObjectType -and $_.IdentityReference -eq $referenceObject.IdentityReference }) if($match.Count -eq 0) From d4ed5f7d2326ab62f278cee7b2eba0e40addee2f Mon Sep 17 00:00:00 2001 From: Reggie Gibson Date: Thu, 18 Jan 2018 21:40:46 -0500 Subject: [PATCH 3/6] ActiveDirectoryAccessEntry unit test; resource fixes --- .../AccessControlResourceHelper.psm1 | 51 +++ .../ActiveDirectoryAccessEntry.psm1 | 169 +++------ .../ActiveDirectoryAuditRuleEntry.psm1 | 50 --- Tests/TestHelper.psm1 | 98 +++++ .../Unit/ActiveDirectoryAccessEntry.Tests.ps1 | 351 ++++++++++++++++++ 5 files changed, 551 insertions(+), 168 deletions(-) create mode 100644 Tests/Unit/ActiveDirectoryAccessEntry.Tests.ps1 diff --git a/DscResources/AccessControlResourceHelper/AccessControlResourceHelper.psm1 b/DscResources/AccessControlResourceHelper/AccessControlResourceHelper.psm1 index ada0edf..7bc36be 100644 --- a/DscResources/AccessControlResourceHelper/AccessControlResourceHelper.psm1 +++ b/DscResources/AccessControlResourceHelper/AccessControlResourceHelper.psm1 @@ -118,3 +118,54 @@ function ConvertTo-SID } } + +function Assert-Module +{ + [CmdletBinding()] + param + ( + [Parameter()] [ValidateNotNullOrEmpty()] + [System.String] + $ModuleName + ) + + if (-not (Get-Module -Name $ModuleName -ListAvailable)) + { + $errorId = '{0}_ModuleNotFound' -f $ModuleName; + $errorMessage = $localizedString.RoleNotFoundError -f $ModuleName; + ThrowInvalidOperationError -ErrorId $errorId -ErrorMessage $errorMessage; + } +} + +Function Get-SchemaIdGuid +{ + Param + ( + [Parameter()] + [string] + $ObjectName + ) + + if($ObjectName) + { + $value = Get-ADObject -filter {name -eq $ObjectName} -SearchBase (Get-ADRootDSE).schemaNamingContext -prop schemaIDGUID + return [system.guid]$value.schemaIDGUID + } + else + { + return [system.guid]"00000000-0000-0000-0000-000000000000" + } +} + +Function Get-SchemaObjectName +{ + Param + ( + [Parameter()] + [guid] + $SchemaIdGuid + ) + + $value = Get-ADObject -filter {schemaIDGUID -eq $SchemaIdGuid} -SearchBase (Get-ADRootDSE).schemaNamingContext -prop schemaIDGUID + return $value.name +} diff --git a/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 b/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 index 31864ce..4827222 100644 --- a/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 +++ b/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.psm1 @@ -30,7 +30,7 @@ Function Get-TargetResource ) Assert-Module -ModuleName 'ActiveDirectory' - Import-Module -Name 'ActiveDirectory' -Verbose:$false + Import-Module -Name 'ActiveDirectory' -Verbose:$false -force $namespace = "root/Microsoft/Windows/DesiredStateConfiguration" $cimAccessControlList = New-Object -TypeName 'System.Collections.ObjectModel.Collection`1[Microsoft.Management.Infrastructure.CimInstance]' @@ -39,7 +39,7 @@ Function Get-TargetResource if(Test-Path -Path $path) { - $currentAcl = Get-Acl -Path $path -ErrorAction Stop + $currentAcl = Get-Acl -Path $path if($null -ne $currentAcl) { @@ -116,7 +116,7 @@ Function Set-TargetResource ) Assert-Module -ModuleName 'ActiveDirectory' - Import-Module -Name 'ActiveDirectory' -Verbose:$false + Import-Module -Name 'ActiveDirectory' -Verbose:$false -force $path = Join-Path -Path "ad:\" -ChildPath $DistinguishedName @@ -125,45 +125,23 @@ Function Set-TargetResource $currentAcl = Get-Acl -Path $path if($null -ne $currentAcl) { - if($Force) + foreach($accessControlItem in $AccessControlList) { - foreach($accessControlItem in $AccessControlList) - { - $principal = $accessControlItem.Principal - $identity = Resolve-Identity -Identity $principal - $identityRef = New-Object System.Security.Principal.NTAccount($identity.Name) + $principal = $accessControlItem.Principal + $identity = Resolve-Identity -Identity $principal + $identityRef = New-Object System.Security.Principal.NTAccount($identity.Name) - $aclRules += ConvertTo-ActiveDirectoryAccessRule -AccessControlList $accessControlItem -IdentityRef $identityRef - } - - $actualAce = $currentAcl.Access + $actualAce = $currentAcl.Access.Where({$_.IdentityReference -eq $identity.Name}) + $aclRules = ConvertTo-ActiveDirectoryAccessRule -AccessControlList $accessControlItem -IdentityRef $identityRef $results = Compare-ActiveDirectoryAccessRule -Expected $aclRules -Actual $actualAce - $expected = $results.Rules - $absentToBeRemoved = $results.Absent - $toBeRemoved = $results.ToBeRemoved - } - else - { - foreach($accessControlItem in $AccessControlList) - { - $principal = $accessControlItem.Principal - $identity = Resolve-Identity -Identity $principal - $identityRef = New-Object System.Security.Principal.NTAccount($identity.Name) - - $actualAce = $currentAcl.Access.Where({$_.IdentityReference -eq $identity.Name}) - - $aclRules = ConvertTo-ActiveDirectoryAccessRule -AccessControlList $accessControlItem -IdentityRef $identityRef - $results = Compare-ActiveDirectoryAccessRule -Expected $aclRules -Actual $actualAce - - $expected += $results.Rules - $absentToBeRemoved += $results.Absent + $expected += $results.Rules + $absentToBeRemoved += $results.Absent - if($accessControlItem.ForcePrinciPal) - { - $toBeRemoved += $results.ToBeRemoved - } + if($accessControlItem.ForcePrinciPal) + { + $toBeRemoved += $results.ToBeRemoved } } @@ -196,7 +174,7 @@ Function Set-TargetResource } } - foreach($rule in $absentToBeRemoved.Rule) + foreach($rule in $absentToBeRemoved) { $nonMatch = $rule.Rule ("Removing Access rule:"), @@ -207,12 +185,12 @@ Function Set-TargetResource ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | - Write-Verbose + Write-Verbose - $currentAcl.RemoveAccessRule($rule) + $currentAcl.RemoveAccessRule($rule.Rule) } - foreach($rule in $toBeRemoved.Rule) + foreach($rule in $toBeRemoved) { $nonMatch = $rule.Rule ("Removing Access rule:"), @@ -223,8 +201,8 @@ Function Set-TargetResource ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | - Write-Verbose - $currentAcl.RemoveAccessRule($rule) + Write-Verbose + $currentAcl.RemoveAccessRule($rule.Rule) } Set-Acl -Path $path -AclObject $currentAcl @@ -258,7 +236,7 @@ Function Test-TargetResource ) Assert-Module -ModuleName 'ActiveDirectory' - Import-Module -Name 'ActiveDirectory' -Verbose:$false + Import-Module -Name 'ActiveDirectory' -Verbose:$false -force $inDesiredState = $True $path = Join-Path -Path "ad:\" -ChildPath $DistinguishedName @@ -313,34 +291,40 @@ Function Test-TargetResource if($absentToBeRemoved.Count -gt 0) { - $nonMatch = $rule.Rule - ("Found [absent] Access rule:"), - ("> Principal : '{0}'" -f $principal), - ("> Path : '{0}'" -f $path), - ("> IdentityReference : '{0}'" -f $nonMatch.IdentityReference), - ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), - ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), - ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), - ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), - ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | - Write-Verbose - $inDesiredState = $False + foreach($rule in $absentToBeRemoved) + { + $nonMatch = $rule.Rule + ("Found [absent] Access rule:"), + ("> Principal : '{0}'" -f $principal), + ("> Path : '{0}'" -f $path), + ("> IdentityReference : '{0}'" -f $nonMatch.IdentityReference), + ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), + ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), + ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), + ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | + Write-Verbose + $inDesiredState = $False + } } if($toBeRemoved.Count -gt 0) { - $nonMatch = $rule.Rule - ("Non-matching Access rule found:"), - ("> Principal : '{0}'" -f $principal), - ("> Path : '{0}'" -f $path), - ("> IdentityReference : '{0}'" -f $nonMatch.IdentityReference), - ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), - ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), - ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), - ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), - ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | - Write-Verbose - $inDesiredState = $False + foreach($rule in $toBeRemoved) + { + $nonMatch = $rule.Rule + ("Non-matching Access rule found:"), + ("> Principal : '{0}'" -f $principal), + ("> Path : '{0}'" -f $path), + ("> IdentityReference : '{0}'" -f $nonMatch.IdentityReference), + ("> ActiveDirectoryRights : '{0}'" -f $nonMatch.ActiveDirectoryRights), + ("> AccessControlType : '{0}'" -f $nonMatch.AccessControlType), + ("> InheritanceType : '{0}'" -f $nonMatch.InheritanceType), + ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.InheritedObjectType)), + ("> ObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $nonMatch.ObjectType)) | + Write-Verbose + $inDesiredState = $False + } } } else @@ -476,54 +460,3 @@ Function Compare-ActiveDirectoryAccessRule Absent = $absentToBeRemoved } } - -function Assert-Module -{ - [CmdletBinding()] - param - ( - [Parameter()] [ValidateNotNullOrEmpty()] - [System.String] - $ModuleName = 'ActiveDirectory' - ) - - if (-not (Get-Module -Name $ModuleName -ListAvailable)) - { - $errorId = '{0}_ModuleNotFound' -f $ModuleName; - $errorMessage = $localizedString.RoleNotFoundError -f $ModuleName; - ThrowInvalidOperationError -ErrorId $errorId -ErrorMessage $errorMessage; - } -} - -Function Get-SchemaIdGuid -{ - Param - ( - [Parameter()] - [string] - $ObjectName - ) - - if($ObjectName) - { - $value = Get-ADObject -filter {name -eq $ObjectName} -SearchBase (Get-ADRootDSE).schemaNamingContext -prop schemaIDGUID - return [system.guid]$value.schemaIDGUID - } - else - { - return [system.guid]"00000000-0000-0000-0000-000000000000" - } -} - -Function Get-SchemaObjectName -{ - Param - ( - [Parameter()] - [guid] - $SchemaIdGuid - ) - - $value = Get-ADObject -filter {schemaIDGUID -eq $SchemaIdGuid} -SearchBase (Get-ADRootDSE).schemaNamingContext -prop schemaIDGUID - return $value.name -} diff --git a/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.psm1 b/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.psm1 index 8af723e..b41ffc9 100644 --- a/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.psm1 +++ b/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.psm1 @@ -501,53 +501,3 @@ Function Compare-ActiveDirectoryAuditRule Absent = $AbsentToBeRemoved } } - -function Assert-Module -{ - [CmdletBinding()] - param - ( - [Parameter()] [ValidateNotNullOrEmpty()] - [System.String] $ModuleName = 'ActiveDirectory' - ) - - if (-not (Get-Module -Name $ModuleName -ListAvailable)) - { - $errorId = '{0}_ModuleNotFound' -f $ModuleName; - $errorMessage = $localizedString.RoleNotFoundError -f $moduleName; - ThrowInvalidOperationError -ErrorId $errorId -ErrorMessage $errorMessage; - } -} - -Function Get-SchemaIdGuid -{ - Param - ( - [Parameter()] - [string] - $ObjectName - ) - - if($ObjectName) - { - $value = Get-ADObject -filter {name -eq $ObjectName} -SearchBase (Get-ADRootDSE).schemaNamingContext -prop schemaIDGUID - return [guid]$value.schemaIDGUID - } - else - { - return [system.guid]"00000000-0000-0000-0000-000000000000" - } -} - -Function Get-SchemaObjectName -{ - Param - ( - [Parameter()] - [guid] - $SchemaIdGuid - ) - - $value = Get-ADObject -filter {schemaIDGUID -eq $SchemaIdGuid} -SearchBase (Get-ADRootDSE).schemaNamingContext -prop schemaIDGUID - return $value.name -} diff --git a/Tests/TestHelper.psm1 b/Tests/TestHelper.psm1 index b6c50ed..93244e0 100644 --- a/Tests/TestHelper.psm1 +++ b/Tests/TestHelper.psm1 @@ -432,3 +432,101 @@ function New-AuditAccessControlList } Return $CimAccessControlList } + +<# + .SYNOPSIS + Creates an Access Control List Ciminstance + + .PARAMETER Principal + Name of the principal which access rights are being managed + + .PARAMETER ForcePrincipal + Used to force the desired access rule + + .PARAMETER AccessControlType + States if the principal should be will be allowed or denied access + + .PARAMETER ActiveDirectoryRights + What rights the principal is being given over an object + + .PARAMETER Inheritance + The inheritance properties of the object being managed + + .PARAMETER InheritedObjectType + The object type the inheritance property applies to + + .PARAMETER ObjectType + The object type the ActiveDirectoryRights applies to + + .PARAMETER Ensure + Either Present or Absent +#> + +function New-ActiveDirectoryAccessControlList +{ + param + ( + [Parameter(Mandatory = $true)] + $Principal, + + [Parameter(Mandatory = $true)] + [boolean] + $ForcePrincipal, + + [Parameter()] + [ValidateSet("Allow","Deny")] + [string] + $AccessControlType, + + [Parameter()] + [ValidateSet("AccessSystemSecurity","CreateChild","Delete","DeleteChild","DeleteTree","ExtendedRight","GenericAll","GenericExecute","GenericRead","GenericWrite","ListChildren","ListObject","ReadControl","ReadProperty","Self","WriteDacl","WriteOwner","WriteProperty")] + $ActiveDirectoryRights, + + [Parameter()] + [ValidateSet("All","Children","Descendents","None","SelfAndChildren")] + [String] + $InheritanceType, + + [Parameter()] + [string] + $InheritedObjectType, + + [Parameter()] + [string] + $ObjectType, + + [Parameter(Mandatory = $true)] + [ValidateSet("Absent", "Present")] + $Ensure + ) + + $NameSpace = "root/Microsoft/Windows/DesiredStateConfiguration" + $CimAccessControlList = New-Object -TypeName 'System.Collections.ObjectModel.Collection`1[Microsoft.Management.Infrastructure.CimInstance]' + $CimAccessControlEntry = New-Object -TypeName 'System.Collections.ObjectModel.Collection`1[Microsoft.Management.Infrastructure.CimInstance]' + + if ($null -eq $ActiveDirectoryRights) + { + $CimAccessControlList += New-CimInstance -ClientOnly -Namespace $NameSpace -ClassName ActiveDirectoryAccessControlList -Property @{ + Principal = $Principal + ForcePrincipal = $ForcePrincipal + } + } + else + { + $CimAccessControlEntry += New-CimInstance -ClientOnly -Namespace $NameSpace -ClassName ActiveDirectoryAccessRule -Property @{ + AccessControlType = $AccessControlType + ActiveDirectoryRights = @($ActiveDirectoryRights) + InheritanceType = $InheritanceType + InheritedObjectType = $InheritedObjectType + ObjectType = $ObjectType + Ensure = $Ensure + } + + $CimAccessControlList += New-CimInstance -ClientOnly -Namespace $NameSpace -ClassName ActiveDirectoryAccessControlList -Property @{ + Principal = $Principal + ForcePrincipal = $ForcePrincipal + AccessControlEntry = [Microsoft.Management.Infrastructure.CimInstance[]]@($CimAccessControlEntry) + } + } + Return $CimAccessControlList +} diff --git a/Tests/Unit/ActiveDirectoryAccessEntry.Tests.ps1 b/Tests/Unit/ActiveDirectoryAccessEntry.Tests.ps1 new file mode 100644 index 0000000..b538efb --- /dev/null +++ b/Tests/Unit/ActiveDirectoryAccessEntry.Tests.ps1 @@ -0,0 +1,351 @@ +#requires -Version 4.0 -Modules Pester + +#region Setup for tests + +$DSCResourceName = 'ActiveDirectoryAccessEntry' + +Import-Module "$($PSScriptRoot)\..\..\DSCResources\$($DSCResourceName)\$($DSCResourceName).psm1" -Force +Import-Module "$($PSScriptRoot)\..\..\DscResources\AccessControlResourceHelper\AccessControlResourceHelper.psm1" -Force +Import-Module "$($PSScriptRoot)\..\TestHelper.psm1" -Force + +#endregion + +InModuleScope ActiveDirectoryAccessEntry { + $DSCResourceName = 'ActiveDirectoryAccessEntry' + Describe "$DSCResourceName\Get-TargetResource" { + + Mock -CommandName Join-Path -MockWith { return "AD:\DC=PowerStig,DC=Local" } -ModuleName $DSCResourceName + Mock -CommandName Test-Path -MockWith { return $true } -ModuleName $DSCResourceName + Mock -CommandName Assert-Module -MockWith {} -ModuleName $DSCResourceName + Mock -CommandName Import-Module -MockWith {} -ParameterFilter {$name -eq 'ActiveDirectory'} -ModuleName $DSCResourceName + + Context "Should return current Access Rules" { + Mock -CommandName Get-Acl -MockWith { + $collection = [System.Security.AccessControl.AuthorizationRuleCollection]::new() + $identity = Resolve-Identity -Identity "Everyone" + $identityRef = [System.Security.Principal.NTAccount]::new($identity.Name) + $activeDirectoryRights = @("Delete","ReadControl") + + foreach($right in $activeDirectoryRights) + { + $accessRule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new($identityRef, [System.DirectoryServices.ActiveDirectoryRights]::$right , [System.Security.AccessControl.AccessControlType]::Allow, ([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit) , [guid]"52ea1a9a-be7e-4213-9e69-5f28cb89b56a") + $collection.AddRule($accessRule) + } + + $acl = @{Access = $collection} + return $acl + } -ModuleName $DSCResourceName + + $tempAcl = New-ActiveDirectoryAccessControlList -Principal "Everyone" -ForcePrincipal $false -AccessControlType Allow -ActiveDirectoryRights GenericAll -InheritanceType All -InheritedObjectType "52ea1a9a-be7e-4213-9e69-5f28cb89b56a" -ObjectType "00000000-0000-0000-0000-000000000000" -Ensure Present + + $contextParams = @{ + DistinguishedName = "DC=PowerStig,DC=Local" + AccessControlList = $tempAcl + } + + $getResult = & "$($DSCResourceName)\Get-TargetResource" @contextParams + + It 'Should return Ensure set as empty' { + [string]::IsNullOrWhiteSpace($getResult.AccessControlList.AccessControlEntry.Ensure) | Should Be $true + } + + It 'Should return DistinguishedName' { + $getResult.DistinguishedName | Should Be "DC=PowerStig,DC=Local" + } + + It 'Should return Principal' { + $getResult.AccessControlList.Principal | Should Be "Everyone" + } + + It 'Should return AccessControlEntries' { + $getResult.AccessControlList.AccessControlEntry.Count | Should Be 2 + } + + It 'Should return InheritanceType' { + $getResult.AccessControlList.AccessControlEntry[0].InheritanceType | Should Be "SelfAndChildren" + } + + It 'Should return AccessControlType' { + $getResult.AccessControlList.AccessControlEntry[0].AccessControlType | Should Be "Allow" + } + } + + Context 'No permissions exist' { + + Mock -CommandName Get-Acl -MockWith { + $collection = [System.Security.AccessControl.AuthorizationRuleCollection]::new() + $acl = @{Access = $collection} + return $acl + } -ModuleName $DSCResourceName + + $tempAcl = New-ActiveDirectoryAccessControlList -Principal "Everyone" -ForcePrincipal $false -AccessControlType Allow -ActiveDirectoryRights GenericAll -InheritanceType All -InheritedObjectType "52ea1a9a-be7e-4213-9e69-5f28cb89b56a" -ObjectType "00000000-0000-0000-0000-000000000000" -Ensure Present + + $contextParams = @{ + DistinguishedName = "DC=PowerStig,DC=Local" + AccessControlList = $tempAcl + } + + $getResult = Get-TargetResource @contextParams + + It 'Should return Ensure set as empty' { + [string]::IsNullOrEmpty($getResult.AccessControl.AccessControlEntry.Ensure) | Should Be $true + } + + It 'Should return DistinguishedName' { + $getResult.DistinguishedName | Should Be $contextParams.DistinguishedName + } + + It 'Should return Principal' { + $getResult.AccessControlList.Principal | Should Be "Everyone" + } + + It 'Should return empty AccessControlEntry' { + $getResult.AccessControlList.AccessControlEntry.Count | Should Be 0 + } + } + } + + Describe "$DSCResourceName\Test-TargetResource" { + + Mock -CommandName Join-Path -MockWith { return "AD:\DC=PowerStig,DC=Local" } -ModuleName $DSCResourceName + Mock -CommandName Test-Path -MockWith { return $true } -ModuleName $DSCResourceName + Mock -CommandName Assert-Module -MockWith {} -ModuleName $DSCResourceName + Mock -CommandName Import-Module -MockWith {} -ParameterFilter {$name -eq 'ActiveDirectory'}-ModuleName $DSCResourceName + Mock -CommandName Get-SchemaIdGuid -MockWith { return [guid]"52ea1a9a-be7e-4213-9e69-5f28cb89b56a" } -ModuleName $DSCResourceName + Mock -CommandName Get-SchemaObjectName -MockWith { return "Pwd-Last-Set" } -ModuleName $DSCResourceName + + Mock -CommandName Get-Acl -MockWith { + $collection = [System.Security.AccessControl.AuthorizationRuleCollection]::new() + $identity = Resolve-Identity -Identity "Everyone" + $identityRef = [System.Security.Principal.NTAccount]::new($identity.Name) + $activeDirectoryRights = @("Delete","ReadControl") + + foreach($right in $activeDirectoryRights) + { + $accessRule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new($identityRef, [System.DirectoryServices.ActiveDirectoryRights]::$right , [System.Security.AccessControl.AccessControlType]::Allow, ([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit) , [guid]"52ea1a9a-be7e-4213-9e69-5f28cb89b56a") + $collection.AddRule($accessRule) + } + + $acl = @{Access = $collection} + return $acl + } -ModuleName $DSCResourceName + + Context "Permissions already exist with ForcePrincipal False" { + + $tempAcl = New-ActiveDirectoryAccessControlList -Principal "Everyone" -ForcePrincipal $false -AccessControlType Allow -ActiveDirectoryRights Delete -InheritanceType SelfAndChildren -InheritedObjectType "52ea1a9a-be7e-4213-9e69-5f28cb89b56a" -Ensure Present + + $contextParams = @{ + DistinguishedName = "DC=PowerStig,DC=Local" + AccessControlList = $tempAcl + } + + $testResult = & "$($DSCResourceName)\Test-TargetResource" @contextParams + + It 'Should return true' { + $testResult | Should Be $true + } + } + + Context "Permissions dont exist with ForcePrincipal False" { + + $tempAcl = New-ActiveDirectoryAccessControlList -Principal "Everyone" -ForcePrincipal $false -AccessControlType Allow -ActiveDirectoryRights CreateChild -InheritanceType SelfAndChildren -InheritedObjectType "52ea1a9a-be7e-4213-9e69-5f28cb89b56a" -Ensure Present + + $contextParams = @{ + DistinguishedName = "DC=PowerStig,DC=Local" + AccessControlList = $tempAcl + } + + $testResult = & "$($DSCResourceName)\Test-TargetResource" @contextParams + + It 'Should return false' { + $testResult | Should Be $false + } + } + + Context "Permissions dont exist with ForcePrincipal true" { + + $tempAcl = New-ActiveDirectoryAccessControlList -Principal "Everyone" -ForcePrincipal $true -AccessControlType Allow -ActiveDirectoryRights CreateChild -InheritanceType SelfAndChildren -InheritedObjectType "52ea1a9a-be7e-4213-9e69-5f28cb89b56a" -Ensure Present + + $contextParams = @{ + DistinguishedName = "DC=PowerStig,DC=Local" + AccessControlList = $tempAcl + } + + $testResult = & "$($DSCResourceName)\Test-TargetResource" @contextParams + + It 'Should return false' { + $testResult | Should Be $false + } + } + + Context "Permissions dont exist with ForcePrincipal false" { + + $tempAcl = New-ActiveDirectoryAccessControlList -Principal "Everyone" -ForcePrincipal $false -AccessControlType Allow -ActiveDirectoryRights CreateChild -InheritanceType SelfAndChildren -InheritedObjectType "52ea1a9a-be7e-4213-9e69-5f28cb89b56a" -Ensure Present + + $contextParams = @{ + DistinguishedName = "DC=PowerStig,DC=Local" + AccessControlList = $tempAcl + } + + $testResult = & "$($DSCResourceName)\Test-TargetResource" @contextParams + + It 'Should return false' { + $testResult | Should Be $false + } + + } + + Context "Multiple permissions already exist with ForcePrincipal true and only one principal required" { + + $tempAcl = New-ActiveDirectoryAccessControlList -Principal "Everyone" -ForcePrincipal $true -AccessControlType Allow -ActiveDirectoryRights Delete -InheritanceType SelfAndChildren -InheritedObjectType "52ea1a9a-be7e-4213-9e69-5f28cb89b56a" -Ensure Present + + $contextParams = @{ + DistinguishedName = "DC=PowerStig,DC=Local" + AccessControlList = $tempAcl + } + + $testResult = & "$($DSCResourceName)\Test-TargetResource" @contextParams + + It 'Should return false' { + $testResult | Should Be $false + } + } + } + + Describe "Helper Functions" { + + Mock -CommandName Join-Path -MockWith { return "AD:\DC=PowerStig,DC=Local" } -ModuleName $DSCResourceName + Mock -CommandName Test-Path -MockWith { return $true } -ModuleName $DSCResourceName + Mock -CommandName Assert-Module -MockWith {} -ModuleName $DSCResourceName + Mock -CommandName Import-Module -MockWith {} -ParameterFilter {$name -eq 'ActiveDirectory'} -ModuleName $DSCResourceName + Mock -CommandName Get-SchemaIdGuid -MockWith { return [guid]"52ea1a9a-be7e-4213-9e69-5f28cb89b56a" } -ModuleName $DSCResourceName + Mock -CommandName Get-SchemaObjectName -MockWith { return "Pwd-Last-Set" } -ModuleName $DSCResourceName + + $identity = Resolve-Identity -Identity "Everyone" + $identityRef = [System.Security.Principal.NTAccount]::new($identity.Name) + $accessRule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new($identityRef, [System.DirectoryServices.ActiveDirectoryRights]::Delete , [System.Security.AccessControl.AccessControlType]::Allow, ([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit) , [guid]"52ea1a9a-be7e-4213-9e69-5f28cb89b56a") + $tempAcl = New-ActiveDirectoryAccessControlList -Principal "Everyone" -ForcePrincipal $false -AccessControlType Allow -ActiveDirectoryRights Delete -InheritanceType SelfAndChildren -InheritedObjectType "52ea1a9a-be7e-4213-9e69-5f28cb89b56a" -ObjectType "00000000-0000-0000-0000-000000000000" -Ensure Present + + Context "ConvertTo-ActiveDirectoryAccessRule" { + + $convertedAccessRule = ConvertTo-ActiveDirectoryAccessRule -AccessControlList $tempAcl -IdentityRef $identityRef + + It 'Should return 1 rule' { + $convertedAccessRule.Rules.Count | Should Be 1 + } + + It 'Should return a pscustomobject' { + $convertedAccessRule.GetType().Name | Should Be "PSCustomObject" + } + + foreach($property in ($accessRule | Get-Member -MemberType Properties)) + { + It "$($property.Name) should match" { + $accessRule.($property.Name) | Should Be $convertedAccessRule.Rules[0].($property.Name) + } + } + } + + Context "Compare-ActiveDirectoryAccessRule with matching rules only" { + + $convertedAccessRule = ConvertTo-ActiveDirectoryAccessRule -AccessControlList $tempAcl -IdentityRef $identityRef + $compare = Compare-ActiveDirectoryAccessRule -Actual $accessRule -Expected $convertedAccessRule + + It 'Should return a pscustomobject' { + $convertedAccessRule.GetType().Name | Should Be "PSCustomObject" + } + + It "Should not have any ToBeRemoved Rules" { + $compare.ToBeRemoved.Count | Should Be 0 + } + + It "Should not have any Absent Rules" { + $compare.Absent.Count | Should Be 0 + } + + It "Should have 1 Rule" { + $compare.Rules.Count | Should Be 1 + } + + It "Returned rule should Match" { + $compare.Rules.Match | Should Be "True" + } + } + + Context "Compare-ActiveDirectoryAccessRule with multiple rules and Expected rule existing" { + + $collection = [System.Security.AccessControl.AuthorizationRuleCollection]::new() + $identity = Resolve-Identity -Identity "Everyone" + $identityRef = [System.Security.Principal.NTAccount]::new($identity.Name) + $identityRef2 = [System.Security.Principal.NTAccount]::new("BUILTIN\Users") + $accessRule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new($identityRef, [System.DirectoryServices.ActiveDirectoryRights]::Delete , [System.Security.AccessControl.AccessControlType]::Allow, ([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit) , [guid]"52ea1a9a-be7e-4213-9e69-5f28cb89b56a") + $accessRule2 = [System.DirectoryServices.ActiveDirectoryAccessRule]::new($identityRef, [System.DirectoryServices.ActiveDirectoryRights]::ReadControl , [System.Security.AccessControl.AccessControlType]::Allow, ([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit) , [guid]"52ea1a9a-be7e-4213-9e69-5f28cb89b56a") + $accessRule3 = [System.DirectoryServices.ActiveDirectoryAccessRule]::new($identityRef2, [System.DirectoryServices.ActiveDirectoryRights]::Delete , [System.Security.AccessControl.AccessControlType]::Allow, ([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit) , [guid]"52ea1a9a-be7e-4213-9e69-5f28cb89b56a") + $collection.AddRule($accessRule) + $collection.AddRule($accessRule2) + $collection.AddRule($accessRule3) + $acl = @{Access = $collection} + + $convertedAccessRule = ConvertTo-ActiveDirectoryAccessRule -AccessControlList $tempAcl -IdentityRef $identityRef + $compare = Compare-ActiveDirectoryAccessRule -Actual $acl.Access -Expected $convertedAccessRule + + It 'Should return a pscustomobject' { + $convertedAccessRule.GetType().Name | Should Be "PSCustomObject" + } + + It "Should not have any ToBeRemoved Rules" { + $compare.ToBeRemoved.Count | Should Be 2 + } + + It "Should not have any Absent Rules" { + $compare.Absent.Count | Should Be 0 + } + + It "Should have 1 Rule" { + $compare.Rules.Count | Should Be 1 + } + + It "Returned rule should Match" { + $compare.Rules.Match | Should Be "True" + } + } + + Context "Compare-ActiveDirectoryAccessRule with multiple rules and Expected not existing existing" { + + $collection = [System.Security.AccessControl.AuthorizationRuleCollection]::new() + $identity = Resolve-Identity -Identity "Everyone" + $identityRefs = @([System.Security.Principal.NTAccount]::new($identity.Name),[System.Security.Principal.NTAccount]::new("BUILTIN\Users")) + + foreach($ref in $identityRefs) + { + $accessRule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new($ref, [System.DirectoryServices.ActiveDirectoryRights]::Delete , [System.Security.AccessControl.AccessControlType]::Deny, ([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit) , [guid]"52ea1a9a-be7e-4213-9e69-5f28cb89b56a") + $collection.AddRule($accessRule) + } + + $acl = @{Access = $collection} + + $convertedAccessRule = ConvertTo-ActiveDirectoryAccessRule -AccessControlList $tempAcl -IdentityRef $identityRef + $compare = Compare-ActiveDirectoryAccessRule -Actual $acl.Access -Expected $convertedAccessRule + + It 'Should return a pscustomobject' { + $convertedAccessRule.GetType().Name | Should Be "PSCustomObject" + } + + It "Should not have any ToBeRemoved Rules" { + $compare.ToBeRemoved.Count | Should Be 2 + } + + It "Should not have any Absent Rules" { + $compare.Absent.Count | Should Be 0 + } + + It "Should have 1 Rule" { + $compare.Rules.Count | Should Be 1 + } + + It "Returned rule should Match" { + $compare.Rules.Match | Should Be "False" + } + } + } +} From 419bfc2de533e6386c08f662552b8bd9c2a5d973 Mon Sep 17 00:00:00 2001 From: Reggie Gibson Date: Thu, 18 Jan 2018 23:15:45 -0500 Subject: [PATCH 4/6] updated readme; added example; mof fixes --- .../ActiveDirectoryAccessEntry.schema.mof | 4 +- .../ActiveDirectoryAuditRuleEntry.schema.mof | 2 +- .../ActiveDirectoryAccessEntry_example.ps1 | 63 +++++++++++++++++++ .../ActiveDirectoryAuditRuleEntry_example.ps1 | 2 +- README.md | 52 ++++++++++++--- 5 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 Examples/ActiveDirectoryAccessEntry_example.ps1 diff --git a/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.schema.mof b/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.schema.mof index 1bed3db..1ae8404 100644 --- a/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.schema.mof +++ b/DscResources/ActiveDirectoryAccessEntry/ActiveDirectoryAccessEntry.schema.mof @@ -2,7 +2,7 @@ class ActiveDirectoryAccessRule { [Required, Description("Indicates whether to allow or deny access to the target item."), ValueMap{"Allow","Deny"}, Values{"Allow","Deny"}] String AccessControlType; - [Required, Description("Specifies the access rights that are assigned to an Active Directory Domain Services object."), ValueMap{"AccessSystemSecurity","CreateChild","Delete","DeleteChild","DeleteTree","ExtendedRight","GenericAll","GenericExecute","GenericRead","GenericWrite","ListChildren","ListObject","ReadControl","ReadProperty","Self","WriteDacl","WriteOwner","WriteProperty"}, Values{"AccessSystemSecurity","CreateAllChildObjects","Delete","DeleteAllChildObjects","DeleteSubtree","AllExtendedRights","FullControl","Execute","Read","Write","ListContents","ListObject","ReadPermissions","ReadAllProperties","AllValidatedWrites","ModifyPermissions","ModifyOwner","WriteAllProperties"}] String ActiveDirectoryRights[]; + [Required, Description("Specifies the access rights that are assigned to an Active Directory Domain Services object."), ValueMap{"AccessSystemSecurity","CreateChild","Delete","DeleteChild","DeleteTree","ExtendedRight","GenericAll","GenericExecute","GenericRead","GenericWrite","ListChildren","ListObject","ReadControl","ReadProperty","Self","WriteDacl","WriteOwner","WriteProperty"}, Values{"AccessSystemSecurity","CreateChild","Delete","DeleteChild","DeleteTree","ExtendedRight","GenericAll","GenericExecute","GenericRead","GenericWrite","ListChildren","ListObject","ReadControl","ReadProperty","Self","WriteDacl","WriteOwner","WriteProperty"}] String ActiveDirectoryRights[]; [Write, Description("Specifies if, and how, ACE information is applied to an object and its descendents."), ValueMap{"1","4","2","0","3"}, Values{"All","Children","Descendents","None","SelfAndChildren"}] String InheritanceType; [Write, Description("Specifies the schema GUID of the object to which the access rule applies.")] String ObjectType; [Write, Description("Specifies the object type name that identifies the type of child object that can inherit this access rule.")] String InheritedObjectType; @@ -21,5 +21,5 @@ class ActiveDirectoryAccessControlList class ActiveDirectoryAccessEntry : OMI_BaseResource { [Key, Description("Indicates the Distinguished Name value for the target Active Directory Object.")] String DistinguishedName; - [Required, Description("Indicates the access control information in the form of an array of instances of the ActiveDirectoryAuditRuleList CIM class."), EmbeddedInstance("ActiveDirectoryAccessControlList")] String AccessControlList[]; + [Required, Description("Indicates the access control information in the form of an array of instances of the ActiveDirectoryAccessControlList CIM class."), EmbeddedInstance("ActiveDirectoryAccessControlList")] String AccessControlList[]; }; diff --git a/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.schema.mof b/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.schema.mof index 7aea321..0381205 100644 --- a/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.schema.mof +++ b/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.schema.mof @@ -2,7 +2,7 @@ class ActiveDirectoryAuditRule { [Required, Description("Specifies the conditions for auditing attempts to access a securable object."), ValueMap{"Success","Failure"}, Values{"Success","Failure"}] String AuditFlags; - [Required, Description("Specifies the access rights that are assigned to an Active Directory Domain Services object."), ValueMap{"AccessSystemSecurity","CreateChild","Delete","DeleteChild","DeleteTree","ExtendedRight","GenericAll","GenericExecute","GenericRead","GenericWrite","ListChildren","ListObject","ReadControl","ReadProperty","Self","WriteDacl","WriteOwner","WriteProperty"}, Values{"AccessSystemSecurity","CreateAllChildObjects","Delete","DeleteAllChildObjects","DeleteSubtree","AllExtendedRights","FullControl","Execute","Read","Write","ListContents","ListObject","ReadPermissions","ReadAllProperties","AllValidatedWrites","ModifyPermissions","ModifyOwner","WriteAllProperties"}] String ActiveDirectoryRights[]; + [Required, Description("Specifies the access rights that are assigned to an Active Directory Domain Services object."), ValueMap{"AccessSystemSecurity","CreateChild","Delete","DeleteChild","DeleteTree","ExtendedRight","GenericAll","GenericExecute","GenericRead","GenericWrite","ListChildren","ListObject","ReadControl","ReadProperty","Self","WriteDacl","WriteOwner","WriteProperty"}, Values{"AccessSystemSecurity","CreateChild","Delete","DeleteChild","DeleteTree","ExtendedRight","GenericAll","GenericExecute","GenericRead","GenericWrite","ListChildren","ListObject","ReadControl","ReadProperty","Self","WriteDacl","WriteOwner","WriteProperty"}] String ActiveDirectoryRights[]; [Write, Description("Specifies if, and how, ACE information is applied to an object and its descendents."), ValueMap{"1","4","2","0","3"}, Values{"All","Children","Descendents","None","SelfAndChildren"}] String InheritanceType; [Write, Description("Specifies the object type name that identifies the type of child object that can inherit this access rule.")] String InheritedObjectType; [Required, ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] String Ensure; diff --git a/Examples/ActiveDirectoryAccessEntry_example.ps1 b/Examples/ActiveDirectoryAccessEntry_example.ps1 new file mode 100644 index 0000000..032b6ec --- /dev/null +++ b/Examples/ActiveDirectoryAccessEntry_example.ps1 @@ -0,0 +1,63 @@ +configuration Sample_ADAccessControl +{ + Import-DscResource -ModuleName AccessControlDsc + node localhost + { + ActiveDirectoryAccessEntry EastOU + { + DistinguishedName = "OU=east,DC=contoso,DC=com" + AccessControlList = @( + ActiveDirectoryAccessControlList + { + Principal = "contoso\Tier3" + ForcePrincipal = $false + AccessControlEntry = @( + ActiveDirectoryAccessRule + { + AccessControlType = 'Allow' + ActiveDirectoryRights = 'FullControl' + InheritanceType = 'Descendents' + Ensure = 'Present' + } + ) + } + ) + } + ActiveDirectoryAccessEntry HelpdeskOU + { + DistinguishedName = "OU=dsc,DC=contoso,DC=com" + AccessControlList = @( + ActiveDirectoryAccessControlList + { + Principal = "contoso\helpdesk" + ForcePrincipal = $true + AccessControlEntry = @( + ActiveDirectoryAccessRule + { + AccessControlType = 'Allow' + ActiveDirectoryRights = 'Delete' + InheritanceType = 'Descendents' + InheritedObjectType = 'organizational-unit' + Ensure = 'Present' + } + ) + } + ActiveDirectoryAccessControlList + { + Principal = "contoso\testgroup" + ForcePrincipal = $true + AccessControlEntry = @( + ActiveDirectoryAccessRule + { + AccessControlType = 'Allow' + ActiveDirectoryRights = 'CreateChild', 'DeleteChild' + InheritanceType = 'all' + ObjectType = 'computer' + Ensure = 'Present' + } + ) + } + ) + } + } +} diff --git a/Examples/ActiveDirectoryAuditRuleEntry_example.ps1 b/Examples/ActiveDirectoryAuditRuleEntry_example.ps1 index f678780..eeeb323 100644 --- a/Examples/ActiveDirectoryAuditRuleEntry_example.ps1 +++ b/Examples/ActiveDirectoryAuditRuleEntry_example.ps1 @@ -15,7 +15,7 @@ configuration Sample_ADAccessControl ActiveDirectoryAuditRule { AuditFlags = 'Success' - ActiveDirectoryRights = 'FullControl' + ActiveDirectoryRights = 'GenericAll' InheritanceType = 'Descendents' Ensure = 'Present' } diff --git a/README.md b/README.md index 58b7617..dc2e172 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct]( https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ]( https://opensource.microsoft.com/codeofconduct/faq/) -or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions +or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. ## Contributing @@ -21,11 +21,42 @@ Please check out common DSC Resources [contributing guidelines]( ## Resources -* **[ActiveDirectoryAuditRule](#ActiveDirectoryAuditRule):** Provides the ability to manage audit access for Active Directory object SACL. +* [**ActiveDirectoryAccessEntry**](#activedirectoryaccessentry): Provides the ability to manage access entries for Active Directory objects. -* **[NtfsAccessEntry](#NtfsAccessEntry):** Provides the ability to manage access entries for NTFS files and directories. +* [**ActiveDirectoryAuditRule**](#activedirectoryauditrule): Provides the ability to manage audit access for Active Directory object SACL. -* **[RegistryAccessEntry](#RegistryAccessEntry):** Provides the ability to manage access entries for Registry objects. +* [**NtfsAccessEntry**](#ntfsaccessentry): Provides the ability to manage access entries for NTFS files and directories. + +* [**RegistryAccessEntry**](#registryaccessentry): Provides the ability to manage access entries for Registry objects. + +### **ActiveDirectoryAccessEntryRule** + +* **[String] DistinguishedName** _(Key)_: Indicates the Distinguished Name value for the target Active Directory Object. + +* **[String] AccessControlList**: Indicates the access control information in the form of an array of instances of the ActiveDirectoryAccessControlList CIM class. Includes the following properties: + + * **[String] Principal:** Indicates the identity of the principal. + + * **[String] AccessControlEntry:** Indicates the access control entry in the form of an array of instances of the AccessControlList CIM class. Includes the following properties: + + * **[String] AccessControlType:** Specifies whether an AccessRule object is used to allow or deny access. _{ Allow | Deny }_ + + * **[String] ActiveDirectoryRights:** Specifies the access rights that are assigned to an Active Directory Domain Services object. _{ AccessSystemSecurity | CreateChild | Delete | DeleteChild | DeleteTree | ExtendedRight | GenericAll | GenericExecute | GenericRead | GenericWrite | ListChildren | ListObject | ReadControl | ReadProperty | Self | WriteDacl | WriteOwner | WriteProperty }_ + + * **[String] Ensure:** Whether the rights should be present or absent. _{ Ensure | Present }_ + + * **[String] InheritanceType:** Specifies if, and how, ACE information is applied to an object and its descendents. _{ All | Children | Descendents | None | SelfAndChildren }_ + + * **[String] InheritedObjectType:** Specifies the object type name that identifies the type of child object that can inherit this access rule. + + * **[String] ObjectType:** Specifies the object type name that identifies the type of child object that can inherit this access rule. + + * [String] ForcePrincipal: Indicates whether the rights for this principal should be forced. Will remove any rights not explicitly defined in the configuration for the principal. + +#### ActiveDirectoryAccessRule Examples + +* [Set Active Directory OU access rules]( + https://github.com/mcollera/AccessControlDsc/blob/master/Examples/ActiveDirectoryAccessEntry_example.ps1) ### **ActiveDirectoryAuditRule** @@ -39,7 +70,7 @@ Please check out common DSC Resources [contributing guidelines]( * **[String] AuditFlags:** Specifies the conditions for auditing attempts to access a securable object. _{ Success | Failure }_ - * **[String] ActiveDirectoryRights:** Specifies the access rights that are assigned to an Active Directory Domain Services object. _{ AccessSystemSecurity | CreateAllChildObjects | Delete | DeleteAllChildObjects | DeleteSubtree | AllExtendedRights | FullControl | Execute | Read | Write | ListContents | ListObject | ReadPermissions | ReadAllProperties | AllValidatedWrites | ModifyPermissions | ModifyOwner | WriteAllProperties }_ + * **[String] ActiveDirectoryRights:** Specifies the access rights that are assigned to an Active Directory Domain Services object. _{ AccessSystemSecurity | CreateChild | Delete | DeleteChild | DeleteTree | ExtendedRight | GenericAll | GenericExecute | GenericRead | GenericWrite | ListChildren | ListObject | ReadControl | ReadProperty | Self | WriteDacl | WriteOwner | WriteProperty }_ * **[String] Ensure:** Whether the rights should be present or absent. _{ Ensure | Present }_ @@ -54,7 +85,7 @@ Please check out common DSC Resources [contributing guidelines]( #### ActiveDirectoryAuditRule Examples * [Set Active Directory OU audit access rules]( - https://github.com/PowerShell/AccessControlDsc/blob/master/Examples/ActiveDirectoryAuditRuleEntry_example.ps1) + https://github.com/mcollera/AccessControlDsc/blob/master/Examples/ActiveDirectoryAuditRuleEntry_example.ps1) ### **NtfsAccessEntry** @@ -81,7 +112,7 @@ Please check out common DSC Resources [contributing guidelines]( #### NtfsAccessEntry Examples * [Set access entries for NTFS folders]( - https://github.com/PowerShell/AccessControlDsc/blob/master/Examples/NtfsAccessEntry_example.ps1) + https://github.com/mcollera/AccessControlDsc/blob/master/Examples/NtfsAccessEntry_example.ps1) ### **RegistryAccessEntry** @@ -108,11 +139,14 @@ Please check out common DSC Resources [contributing guidelines]( #### RegistryAccessEntry Examples * [Configure access entries for registry key]( - https://github.com/PowerShell/AccessControlDsc/blob/master/Examples/RegistryAccessEntry_example.ps1) + https://github.com/mcollera/AccessControlDsc/blob/master/Examples/RegistryAccessEntry_example.ps1) ## Versions -### Unreleased +### 1.1.0.0 + +* Added ActiveDirectoryAccessEntry resource +* **Breaking Change:** Modified ActiveDirectoryAuditRuleEntry *ActiveDirectoryRights* parameter values to match [System.DirectoryServices.ActiveDirectoryRights](https://msdn.microsoft.com/en-us/library/system.directoryservices.activedirectoryrights(v=vs.110).aspx) members ### 1.0.0.0 From aafef0ce966e5e2b30828dfda5cb71fa4d64aaff Mon Sep 17 00:00:00 2001 From: Reggie Gibson Date: Fri, 19 Jan 2018 07:40:27 -0500 Subject: [PATCH 5/6] version rev --- AccessControlDsc.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AccessControlDsc.psd1 b/AccessControlDsc.psd1 index 539ed8c..c8f4c1e 100644 --- a/AccessControlDsc.psd1 +++ b/AccessControlDsc.psd1 @@ -8,7 +8,7 @@ @{ # Version number of this module. - ModuleVersion = '1.0.0.0' + ModuleVersion = '1.1.0.0' # ID used to uniquely identify this module GUID = 'a544c26f-3f96-4c1e-8351-1604867aafc5' From 71fb50e4c41087fd82af1cd447541619877c032f Mon Sep 17 00:00:00 2001 From: Reggie Gibson Date: Sat, 20 Jan 2018 22:26:52 -0500 Subject: [PATCH 6/6] AuditRule fixes --- .../AccessControlResourceHelper.psm1 | 9 ++++++++- .../ActiveDirectoryAuditRuleEntry.psm1 | 8 ++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/DscResources/AccessControlResourceHelper/AccessControlResourceHelper.psm1 b/DscResources/AccessControlResourceHelper/AccessControlResourceHelper.psm1 index 7bc36be..df95535 100644 --- a/DscResources/AccessControlResourceHelper/AccessControlResourceHelper.psm1 +++ b/DscResources/AccessControlResourceHelper/AccessControlResourceHelper.psm1 @@ -166,6 +166,13 @@ Function Get-SchemaObjectName $SchemaIdGuid ) + If($SchemaIdGuid) + { $value = Get-ADObject -filter {schemaIDGUID -eq $SchemaIdGuid} -SearchBase (Get-ADRootDSE).schemaNamingContext -prop schemaIDGUID - return $value.name + return $value.name + } + else + { + return "none" + } } diff --git a/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.psm1 b/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.psm1 index b41ffc9..33727ae 100644 --- a/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.psm1 +++ b/DscResources/ActiveDirectoryAuditRuleEntry/ActiveDirectoryAuditRuleEntry.psm1 @@ -203,7 +203,7 @@ Function Set-TargetResource } } - foreach($Rule in $AbsentToBeRemoved.Rule) + foreach($Rule in $AbsentToBeRemoved) { $NonMatch = $Rule.Rule ("Removing audit rule:"), @@ -215,10 +215,10 @@ Function Set-TargetResource ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $NonMatch.InheritedObjectType)) | Write-Verbose - $currentAcl.RemoveAuditRule($Rule) + $currentAcl.RemoveAuditRule($Rule.Rule) } - foreach($Rule in $ToBeRemoved.Rule) + foreach($Rule in $ToBeRemoved) { $NonMatch = $Rule.Rule ("Removing audit rule:"), @@ -229,7 +229,7 @@ Function Set-TargetResource ("> InheritanceType : '{0}'" -f $NonMatch.InheritanceType), ("> InheritedObjectType : '{0}'" -f $(Get-SchemaObjectName -SchemaIdGuid $NonMatch.InheritedObjectType)) | Write-Verbose - $currentAcl.RemoveAuditRule($Rule) + $currentAcl.RemoveAuditRule($Rule.Rule) } Set-Acl -Path $Path -AclObject $currentAcl