From b3e9ddeb64962e8dd9581e8be17e5b7c1b14d1b0 Mon Sep 17 00:00:00 2001 From: Przemyslaw Klys Date: Sun, 17 Oct 2021 14:55:27 +0200 Subject: [PATCH] New function, for now internal use --- Private/Get-ADOrganizationalUnitObject.ps1 | 220 +++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 Private/Get-ADOrganizationalUnitObject.ps1 diff --git a/Private/Get-ADOrganizationalUnitObject.ps1 b/Private/Get-ADOrganizationalUnitObject.ps1 new file mode 100644 index 0000000..3c64626 --- /dev/null +++ b/Private/Get-ADOrganizationalUnitObject.ps1 @@ -0,0 +1,220 @@ +function Get-ADOrganizationalUnitObject { + <# + .SYNOPSIS + Gets number of objects in a given OU/OUs with ability to find only those being affected by GPOs. + + .DESCRIPTION + Gets number of objects in a given OU/OUs with ability to find only those being affected by GPOs. + + .PARAMETER OrganizationalUnit + One or more organizational units to get the number of objects in. + + .PARAMETER Extended + Adds all objects affected for better understanding + + .PARAMETER Summary + Returns only summary for given OU/OUs + + .PARAMETER IncludeAffectedOnly + Ignores any object types that are not Users or Computers + + .PARAMETER Forest + Target different Forest, by default current forest is used + + .PARAMETER ExcludeDomains + Exclude domain from search, by default whole forest is scanned + + .PARAMETER IncludeDomains + Include only specific domains, by default whole forest is scanned + + .PARAMETER AsHashTable + Returns results in form of hashtable + + .PARAMETER ExtendedForestInformation + Ability to provide Forest Information from another command to speed up processing + + .EXAMPLE + $OUs = @( + 'OU=SE,OU=ITR01,DC=ad,DC=evotec,DC=xyz' + 'OU=US,OU=ITR01,DC=ad,DC=evotec,DC=xyz' + 'OU=ITR01,DC=ad,DC=evotec,DC=xyz' + 'OU=Users,OU=User,OU=SE1,OU=SE,OU=ITR01,DC=ad,DC=evotec,DC=xyz' + ) + + Get-ADOrganizationalUnitObject -OrganizationalUnit $OUs -IncludeAffectedOnly | Format-Table + + .EXAMPLE + $OUs = @( + 'OU=SE,OU=ITR01,DC=ad,DC=evotec,DC=xyz' + 'OU=US,OU=ITR01,DC=ad,DC=evotec,DC=xyz' + 'OU=ITR01,DC=ad,DC=evotec,DC=xyz' + 'OU=Users,OU=User,OU=SE1,OU=SE,OU=ITR01,DC=ad,DC=evotec,DC=xyz' + ) + + Get-ADOrganizationalUnitObject -OrganizationalUnit $OUs | Format-Table + + .EXAMPLE + $OUs = @( + #'OU=SE,OU=ITR01,DC=ad,DC=evotec,DC=xyz' + #'OU=US,OU=ITR01,DC=ad,DC=evotec,DC=xyz' + 'OU=Users,OU=User,OU=SE1,OU=SE,OU=ITR01,DC=ad,DC=evotec,DC=xyz' + 'OU=ITR01,DC=ad,DC=evotec,DC=xyz' + ) + + Get-ADOrganizationalUnitObject -OrganizationalUnit $OUs -Summary -IncludeAffectedOnly | Format-List + + .NOTES + General notes + #> + [cmdletBinding()] + param( + [parameter(Mandatory)][Array] $OrganizationalUnit, + [switch] $Extended, + [switch] $Summary, + [switch] $IncludeAffectedOnly, + + [alias('ForestName')][string] $Forest, + [string[]] $ExcludeDomains, + [alias('Domain', 'Domains')][string[]] $IncludeDomains, + [switch] $AsHashTable, + [System.Collections.IDictionary] $ExtendedForestInformation + ) + + $CachedOu = [ordered] @{} + $ListOU = @( + foreach ($OU in $OrganizationalUnit) { + if ($OU.DistinguishedName) { + $OU.DistinguishedName + } else { + $OU + } + } + ) + $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation + $OUCache = Get-GPOBlockedInheritance -AsHashTable -ExtendedForestInformation $ForestInformation + + if ($Summary) { + $SummaryData = [ordered] @{ + ObjectsClasses = [ordered] @{} + ObjectsTotalCount = 0 + ObjectsBlockedInheritanceCount = 0 + ObjectsTotal = [ordered] @{} + ObjectsBlockedInheritance = [ordered] @{} + DistinguishedName = [System.Collections.Generic.List[string]]::new() + } + } + + foreach ($OU in $ListOU) { + $Domain = ConvertFrom-DistinguishedName -ToDomainCN -DistinguishedName $OU + $ObjectsInOu = Get-ADObject -LDAPFilter "(|(ObjectClass=user)(ObjectClass=contact)(ObjectClass=computer)(ObjectClass=group)(objectClass=inetOrgPerson))" -SearchBase $OU -Server $ForestInformation['QueryServers'][$Domain]['hostname'][0] + #Write-Verbose "Get-GPOZaurrOrganizationalUnit - Processing $($Domain) / $($TOPOU.DistinguishedName) [$CountTop/$($TopOrganizationalUnits.Count)], found $($ObjectsInOu.Count) objects to process." + if (-not $CachedOu[$OU]) { + $CachedOu[$OU] = [ordered] @{ + DistinguishedName = $OU + Domain = $Domain + 'ObjectsClasses' = [ordered] @{} # only direct, indirect, but not with blocked inheritance + 'ObjectsDirectCount' = 0 + 'ObjectsIndirectCount' = 0 + 'ObjectsTotalCount' = 0 + 'ObjectsTotalIncludingBlockedCount' = 0 + 'ObjectsBlockedInheritanceCount' = 0 + } + if ($Extended) { + $CachedOu[$OU]['ObjectsDirect'] = [ordered] @{} + $CachedOu[$OU]['ObjectsIndirect'] = [ordered] @{} + $CachedOu[$OU]['ObjectsTotal'] = [ordered] @{} + $CachedOu[$OU]['ObjectsTotalIncludingBlocked'] = [ordered] @{} + $CachedOu[$OU]['ObjectsBlockedInheritance'] = [ordered] @{} + } + } + foreach ($Object in $ObjectsInOu) { + if ($IncludeAffectedOnly) { + if ($Object.ObjectClass -notin 'User', 'computer') { + continue + } + } + + $Place = ConvertFrom-DistinguishedName -ToOrganizationalUnit -DistinguishedName $Object.DistinguishedName + if (-not $Place) { + # Write-Verbose -Message "Get-OrganizationalUnitObject - Processing object in container/root $($Object.DistinguishedName)" + } + + if ($Place -and $OUCache[$Place]) { + $BlockedInheritance = $OUCache[$Place].BlockedInheritance + } else { + $BlockedInheritance = $false + } + + if ($Summary) { + $SummaryData['DistinguishedName'].Add($OU) + $SummaryData['ObjectsClasses'][$Object.ObjectClass] = '' + if (-not $Place -or $Place -eq $OU) { + $SummaryData['ObjectsTotal'][$Object.DistinguishedName] = $Object + } else { + if ($BlockedInheritance) { + $SummaryData['ObjectsBlockedInheritance'][$Object.DistinguishedName] = $Object + } else { + $SummaryData['ObjectsTotal'][$Object.DistinguishedName] = $Object + } + } + } else { + # This is standard way of finding OU's + if (-not $Place -or $Place -eq $OU) { + $CachedOu[$OU]['ObjectsDirectCount']++ + $CachedOu[$OU]['ObjectsTotalCount']++ + # using hashtable to avoid duplicates + $CachedOu[$OU]['ObjectsClasses'][$Object.ObjectClass] = '' + # adding all objects to the list, excluding blocked inheritance + if ($Extended) { + $CachedOu[$OU]['ObjectsTotal'][$Object.DistinguishedName] = $Object + $CachedOu[$OU]['ObjectsDirect'][$Object.DistinguishedName] = $Object + } + } else { + if ($BlockedInheritance) { + # We only check for blocked inheritance if the object is not in the same OU + $CachedOu[$OU]['ObjectsBlockedInheritanceCount']++ + if ($Extended) { + $CachedOu[$OU]['ObjectsBlockedInheritance'][$Object.DistinguishedName] = $Object + } + } else { + $CachedOu[$OU]['ObjectsIndirectCount']++ + $CachedOu[$OU]['ObjectsTotalCount']++ + + # using hashtable to avoid duplicates + $CachedOu[$OU]['ObjectsClasses'][$Object.ObjectClass] = '' + # adding all objects to the list excluding blocked inheritance + if ($Extended) { + $CachedOu[$OU]['ObjectsTotal'][$Object.DistinguishedName] = $Object + $CachedOu[$OU]['ObjectsIndirect'][$Object.DistinguishedName] = $Object + } + } + } + $CachedOu[$OU]['ObjectsTotalIncludingBlockedCount']++ + if ($Extended) { + $CachedOu[$OU]['ObjectsTotalIncludingBlocked'][$Object.DistinguishedName] = $Object + } + } + } + + } + if ($Summary) { + foreach ($ObjectDistinguishedName in [string[]] $SummaryData['ObjectsBlockedInheritance'].Keys) { + if ($SummaryData['ObjectsTotal'][$ObjectDistinguishedName]) { + $SummaryData['ObjectsBlockedInheritance'].Remove($ObjectDistinguishedName) + } + } + $SummaryData['ObjectsTotalCount'] = $SummaryData['ObjectsTotal'].Count + $SummaryData['ObjectsBlockedInheritanceCount'] = $SummaryData['ObjectsBlockedInheritance'].Count + if (-not $Extended) { + $SummaryData.Remove('ObjectsTotal') + $SummaryData.Remove('ObjectsBlockedInheritance') + } + [PSCustomObject] $SummaryData + } else { + if ($AsHashTable) { + $CachedOu + } else { + $CachedOu.Values | ForEach-Object { [PSCustomObject] $_ } + } + } +} \ No newline at end of file