Compare commits

...

26 Commits

Author SHA1 Message Date
Przemyslaw Klys 304f70a4d9 PSD1 update 2021-01-02 16:40:03 +01:00
Przemyslaw Klys ab6c61ac52 Update ReADME 2021-01-02 16:39:58 +01:00
Przemyslaw Klys dbe79a7833 Update PSD1 2020-12-28 12:15:35 +01:00
Przemyslaw Klys 0cc05c4aeb Update readme 2020-12-28 12:06:46 +01:00
Przemyslaw Klys c10a4c088e Improved GPOZaurr 2020-12-28 12:06:40 +01:00
Przemyslaw Klys 015afd69a4 Update 2020-12-28 11:53:29 +01:00
Przemyslaw Klys 2fa9b202bc Example updates 2020-12-28 11:42:30 +01:00
Przemyslaw Klys 25bbf8d52e Update 2020-12-28 11:42:04 +01:00
Przemyslaw Klys 8a009bf288 Update 2020-12-28 11:16:59 +01:00
Przemyslaw Klys ed76fc9513 Update example 2020-12-28 10:31:56 +01:00
Przemyslaw Klys 646c22bdab Update example 2020-12-28 10:31:35 +01:00
Przemyslaw Klys d4f8cdc8e8 Update examples 2020-12-28 10:31:25 +01:00
Przemyslaw Klys 166d4fb767 Impoved Get-GPOzaurr Links 2020-12-28 10:30:56 +01:00
Przemyslaw Klys 0ca98a4165 Improvement to links 2020-12-28 10:04:56 +01:00
Przemyslaw Klys a5bcbbf285 Update 2020-12-28 10:04:27 +01:00
Przemyslaw Klys 513179fd03 Invoke-GPOZaurrPermission improvement 2020-12-28 10:04:15 +01:00
Przemyslaw Klys 72cd1da9ae update readme 2020-12-28 10:03:29 +01:00
Przemyslaw Klys 3fe52c99b5 Private use only 2020-12-28 09:55:14 +01:00
Przemyslaw Klys fc6fe14579 Update readme 2020-12-27 23:25:34 +01:00
Przemyslaw Klys bd5a73439d Update 2020-12-27 23:25:15 +01:00
Przemyslaw Klys 469332e543 PSD1 update 2020-12-27 22:38:57 +01:00
Przemyslaw Klys 6cbe3a375a Improved Get-GPOZaurrLink 2020-12-27 22:38:48 +01:00
Przemyslaw Klys c987ca9863 Update 2020-12-27 22:38:31 +01:00
Przemyslaw Klys f0d24e1902 Update 2020-12-27 22:38:05 +01:00
Przemyslaw Klys 61b9c916e7 Update 2020-12-24 09:32:15 +01:00
Przemyslaw Klys deebcb825d Update Get-GPOZaurrLink 2020-12-24 09:27:57 +01:00
23 changed files with 836 additions and 267 deletions
@@ -0,0 +1,5 @@
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
$SummaryHashtable = Get-GPOZaurrLink -AsHashTable -Summary
$SummaryHashtable | Format-Table -AutoSize
$SummaryHashtable[5]
+1 -1
View File
@@ -2,6 +2,6 @@
Get-GPOZaurrLink -SearchBase 'OU=Domain Controllers,DC=ad,DC=evotec,DC=xyz' | Format-Table -AutoSize
Get-GPOZaurrLink -SearchBase 'OU=Computers,OU=Production,DC=ad,DC=evotec,DC=xyz' | Format-Table -AutoSize
Get-GPOZaurrLink -SearchBase 'OU=Accounts,OU=Production,DC=ad,DC=evotec,DC=xyz' | Format-Table -AutoSize
Get-GPOZaurrLink -SearchBase 'DC=ad,DC=evotec,DC=xyz' -SearchScope Base | Format-Table -AutoSize
+3 -2
View File
@@ -1,6 +1,7 @@
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
Get-ADOrganizationalUnit -Filter * -Properties distinguishedName, LinkedGroupPolicyObjects | Get-GPOZaurrLink | Format-Table
Get-ADOrganizationalUnit -Filter * -Properties canonicalname, distinguishedName, LinkedGroupPolicyObjects | Get-GPOZaurrLink | Format-Table
# gpLink is required property. While LinkedGroupPolicyObjects does work it doesn't contain information about enabled/enforced GPO
Get-ADOrganizationalUnit -Filter * -Properties distinguishedName, LinkedGroupPolicyObjects, gpLink | Get-GPOZaurrLink | Format-Table
Get-ADOrganizationalUnit -Filter * -Properties canonicalname, distinguishedName, LinkedGroupPolicyObjects, gpLink | Get-GPOZaurrLink | Format-Table
Get-ADObject -Filter * -Properties distinguishedName, gplink -Server 'ad.evotec.pl' | Get-GPOZaurrLink | Format-Table -AutoSize
Get-GPOZaurrLink | Format-Table -AutoSize
@@ -0,0 +1,3 @@
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
Get-GPOZaurrLink -Site 'Katowice-1','Katowice-2' | Format-Table -AutoSize *
@@ -0,0 +1,3 @@
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
Get-GPOZaurrLink -Linked Site | Format-Table -AutoSize *
@@ -0,0 +1,8 @@
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
$Summary = Get-GPOZaurrLink -Summary
$Summary | Format-Table -AutoSize *
$OneGPO = $Summary | Where-Object { $_.DisplayName -eq 'ALL | Enable RDP' }
$OneGPO.Links
$OneGPO.LinksObjects | Format-Table *
+1 -1
View File
@@ -8,7 +8,7 @@ Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
#Get-GPOZaurrLinkSummary -Report 'LinksSummary' -UnlimitedProperties | Format-Table *
$Report = Get-GPOZaurrLinkSummary #-UnlimitedProperties
$Report | Format-Table *
$Report | Format-Table
$Report.MultipleLinks | Format-Table *
$Report.OneLink | Format-Table *
$Report.LinksSummary | Format-Table *
+1 -1
View File
@@ -5,7 +5,7 @@ $Types = @(
@{ Name = 'GPOConsistency'; Path = "$PSScriptRoot\Reports\GPOConsistency.html" }
@{ Name = 'GPODuplicates'; Path = "$PSScriptRoot\Reports\GPODuplicates.html" }
@{ Name = 'GPOList'; Path = "$PSScriptRoot\Reports\GPOList.html" }
@{ Name = 'GPOOrphans'; Path = "$PSScriptRoot\Reports\GPOOrphans.html" }
@{ Name = 'GPOBroken'; Path = "$PSScriptRoot\Reports\GPOOrphans.html" }
@{ Name = 'GPOPassword'; Path = "$PSScriptRoot\Reports\GPOPassword.html" }
@{ Name = 'NetLogonPermissions'; Path = "$PSScriptRoot\Reports\NetLogonPermissions.html" }
)
+2 -2
View File
@@ -4,11 +4,11 @@
CmdletsToExport = @()
CompanyName = 'Evotec'
CompatiblePSEditions = @('Desktop')
Copyright = '(c) 2011 - 2020 Przemyslaw Klys @ Evotec. All rights reserved.'
Copyright = '(c) 2011 - 2021 Przemyslaw Klys @ Evotec. All rights reserved.'
Description = 'Group Policy Eater is a PowerShell module that aims to gather information about Group Policies but also allows fixing issues that you may find in them.'
FunctionsToExport = @('Add-GPOPermission', 'Add-GPOZaurrPermission', 'Backup-GPOZaurr', 'Clear-GPOZaurrSysvolDFSR', 'ConvertFrom-CSExtension', 'Find-CSExtension', 'Get-GPOZaurr', 'Get-GPOZaurrAD', 'Get-GPOZaurrBackupInformation', 'Get-GPOZaurrBroken', 'Get-GPOZaurrDictionary', 'Get-GPOZaurrDuplicateObject', 'Get-GPOZaurrFiles', 'Get-GPOZaurrFilesPolicyDefinition', 'Get-GPOZaurrFolders', 'Get-GPOZaurrInheritance', 'Get-GPOZaurrLegacyFiles', 'Get-GPOZaurrLink', 'Get-GPOZaurrLinkSummary', 'Get-GPOZaurrNetLogon', 'Get-GPOZaurrOwner', 'Get-GPOZaurrPassword', 'Get-GPOZaurrPermission', 'Get-GPOZaurrPermissionAnalysis', 'Get-GPOZaurrPermissionConsistency', 'Get-GPOZaurrPermissionIssue', 'Get-GPOZaurrPermissionRoot', 'Get-GPOZaurrPermissionSummary', 'Get-GPOZaurrSysvolDFSR', 'Get-GPOZaurrWMI', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrContent', 'Invoke-GPOZaurrPermission', 'Invoke-GPOZaurrSupport', 'New-GPOZaurrWMI', 'Optimize-GPOZaurr', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrBroken', 'Remove-GPOZaurrDuplicateObject', 'Remove-GPOZaurrFolders', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrNetLogonOwner', 'Repair-GPOZaurrPermission', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Set-GPOOwner', 'Set-GPOZaurrOwner', 'Set-GPOZaurrStatus', 'Skip-GroupPolicy')
GUID = 'f7d4c9e4-0298-4f51-ad77-e8e3febebbde'
ModuleVersion = '0.0.101'
ModuleVersion = '0.0.102'
PowerShellVersion = '5.1'
PrivateData = @{
PSData = @{
+39
View File
@@ -0,0 +1,39 @@
function Get-GPOPrivInheritance {
[cmdletBinding()]
param(
[parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
[System.Collections.IDictionary] $CacheReturnedGPOs,
[System.Collections.IDictionary] $ForestInformation,
[string] $Domain,
[switch] $SkipDomainRoot,
[switch] $SkipDomainControllers
)
foreach ($Object in $ADObject) {
if ($SkipDomainRoot) {
if ($Object.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']) {
# other skips Domain Root
continue
}
}
if ($SkipDomainControllers) {
if ($Object.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']) {
# other skips Domain Controllers
continue
}
}
$Inheritance = Get-GPInheritance -Target $Object.DistinguishedName
foreach ($Link in $Inheritance.GpoLinks) {
[PSCustomObject] @{
DisplayName = $Link.DisplayName
DomainName = $Domain
GUID = $Link.GPOID
Enabled = $Link.Enabled
Enforced = $Link.Enforced
Order = $Link.Order
Target = $Object.DistinguishedName
TargetCanonical = $Object.CanonicalName
TargetObjectClass = $Object.objectClass
}
}
}
}
+92
View File
@@ -0,0 +1,92 @@
function Get-GPOPrivInheritanceLoop {
[cmdletBinding()]
param(
[Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
[System.Collections.IDictionary] $CacheReturnedGPOs,
[System.Collections.IDictionary] $ForestInformation,
[validateset('Root', 'DomainControllers', 'OrganizationalUnit')][string[]] $Linked,
[string] $SearchBase,
[Microsoft.ActiveDirectory.Management.ADSearchScope] $SearchScope,
[string] $Filter
)
if (-not $ADObject) {
if ($Linked) {
foreach ($Domain in $ForestInformation.Domains) {
$Splat = @{
#Filter = $Filter
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
# Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
}
if ($Linked -contains 'DomainControllers') {
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
$Splat['SearchBase'] = $SearchBase
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
Get-GPOPrivInheritance -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation
}
if ($Linked -contains 'Root') {
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
$Splat['Filter'] = "objectClass -eq 'domainDNS'"
$Splat['SearchBase'] = $SearchBase
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
Get-GPOPrivInheritance -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation
}
if ($Linked -contains 'Site') {
# Sites are defined only in primary domain
# Sites are not supported by Get-GPInheritance
}
if ($Linked -contains 'OrganizationalUnit') {
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
$Splat['SearchBase'] = $SearchBase
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
Get-GPOPrivInheritance -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -SkipDomainRoot -SkipDomainControllers
}
}
} elseif ($Filter) {
foreach ($Domain in $ForestInformation.Domains) {
$Splat = @{
Filter = $Filter
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
}
if ($PSBoundParameters.ContainsKey('SearchBase')) {
$DomainDistinguishedName = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
$SearchBaseDC = ConvertFrom-DistinguishedName -DistinguishedName $SearchBase -ToDC
if ($SearchBaseDC -ne $DomainDistinguishedName) {
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
continue
}
$Splat['SearchBase'] = $SearchBase
}
if ($PSBoundParameters.ContainsKey('SearchScope')) {
$Splat['SearchScope'] = $SearchScope
}
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
Get-GPOPrivInheritance -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation
}
}
} else {
Get-GPOPrivInheritance -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObject -Domain '' -ForestInformation $ForestInformation
}
}
+39
View File
@@ -0,0 +1,39 @@
function Get-GPOPrivLink {
[cmdletBinding()]
param(
[parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
[System.Collections.IDictionary] $CacheReturnedGPOs,
[System.Collections.IDictionary] $ForestInformation,
[string] $Domain,
[switch] $SkipDomainRoot,
[switch] $SkipDomainControllers,
[switch] $AsHashTable,
[switch] $SkipDuplicates
)
foreach ($Object in $ADObject) {
if ($SkipDomainRoot) {
if ($Object.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']) {
# other skips Domain Root
continue
}
}
if ($SkipDomainControllers) {
if ($Object.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']) {
# other skips Domain Controllers
continue
}
}
$OutputGPOs = Get-PrivGPOZaurrLink -Object $Object -Limited:$Limited.IsPresent -GPOCache $GPOCache
foreach ($OutputGPO in $OutputGPOs) {
if (-not $SkipDuplicates) {
$OutputGPO
} else {
$UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid)
if (-not $CacheReturnedGPOs[$UniqueGuid]) {
$CacheReturnedGPOs[$UniqueGuid] = $OutputGPO
$OutputGPO
}
}
}
}
}
+197
View File
@@ -0,0 +1,197 @@
function Get-GPOZaurrLinkInheritance {
<#
.SYNOPSIS
Short description
.DESCRIPTION
Long description
.PARAMETER ADObject
Parameter description
.PARAMETER Filter
Parameter description
.PARAMETER SearchBase
Parameter description
.PARAMETER SearchScope
Parameter description
.PARAMETER Linked
Parameter description
.PARAMETER Limited
Parameter description
.PARAMETER SkipDuplicates
Parameter description
.PARAMETER GPOCache
Parameter description
.PARAMETER Forest
Parameter description
.PARAMETER ExcludeDomains
Parameter description
.PARAMETER IncludeDomains
Parameter description
.PARAMETER ExtendedForestInformation
Parameter description
.PARAMETER AsHashTable
Parameter description
.PARAMETER Summary
Parameter description
.EXAMPLE
$Output = Get-GPOZaurrLinkInheritance -Summary
$Output | Format-Table
$Output[5]
$Output[5].Links | Format-Table
$Output[5].LinksObjects | Format-Table
.NOTES
This is based on Get-GPInheritance which isn't ideal and doesn't support sites. Get-GPOZaurrLink is better. Leaving in case I need it later on for private use only.
#>
[cmdletbinding(DefaultParameterSetName = 'All')]
param(
[parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
# weirdly enough site doesn't really work this way unless you give it 'CN=Configuration,DC=ad,DC=evotec,DC=xyz' as SearchBase
[parameter(ParameterSetName = 'Filter')][string] $Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')",
[parameter(ParameterSetName = 'Filter')][string] $SearchBase,
[parameter(ParameterSetName = 'Filter')][Microsoft.ActiveDirectory.Management.ADSearchScope] $SearchScope,
[parameter(ParameterSetName = 'Linked', Mandatory)][validateset('Root', 'DomainControllers', 'OrganizationalUnit')][string[]] $Linked,
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[switch] $Limited,
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[switch] $SkipDuplicates,
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[System.Collections.IDictionary] $GPOCache,
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[alias('ForestName')][string] $Forest,
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[string[]] $ExcludeDomains,
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[System.Collections.IDictionary] $ExtendedForestInformation,
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[switch] $AsHashTable,
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[switch] $Summary
)
Begin {
$CacheReturnedGPOs = [ordered] @{}
$ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
if (-not $GPOCache -and -not $Limited) {
$GPOCache = @{ }
# While initially we used $ForestInformation.Domains but the thing is GPOs can be linked to other domains so we need to get them all so we can use cache of it later on even if we're processing just one domain
# That's why we use $ForestInformation.Forest.Domains instead
foreach ($Domain in $ForestInformation.Forest.Domains) {
$QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
Get-GPO -All -DomainName $Domain -Server $QueryServer | ForEach-Object {
$GPOCache["$Domain$($_.ID.Guid)"] = $_
}
}
}
}
Process {
if (-not $Filter -and -not $Linked) {
# We choose ALL, except SITE which is not supported gor Get-GPInheritance
# that's why it's better to use Get-GPOZaurrLink
#$Linked = 'Root', 'DomainControllers', 'Site', 'OrganizationalUnit'
}
$getGPOPrivInheritanceLoopSplat = @{
Linked = $Linked
ForestInformation = $ForestInformation
CacheReturnedGPOs = $CacheReturnedGPOs
SearchScope = $SearchScope
SearchBase = $SearchBase
ADObject = $ADObject
Filter = $Filter
}
Remove-EmptyValue -Hashtable $getGPOPrivInheritanceLoopSplat -Recursive
# we need to use nested functions to support pipeline output and as hashtable and reporting that returns single value
if ($AsHashTable -or $Summary) {
$HashTable = [ordered] @{}
$SummaryHashtable = [ordered] @{}
$Links = Get-GPOPrivInheritanceLoop @getGPOPrivInheritanceLoopSplat
foreach ($Link in $Links) {
$Key = -join ($Link.DomainName, $Link.GUID)
if (-not $HashTable[$Key]) {
$HashTable[$Key] = [System.Collections.Generic.List[PSCustomObject]]::new()
}
$HashTable[$Key].Add($Link)
}
foreach ($Key in $HashTable.Keys) {
[Array] $Link = $HashTable[$Key]
$EnabledLinks = $Link.Enabled.Where( { $_ -eq $true }, 'split')
if ($EnabledLinks[0].Count -gt 0) {
$IsLinked = $true
} else {
$IsLinked = $false
}
$SummaryLink = [PSCustomObject] @{
DisplayName = $Link[0].DisplayName
DomainName = $Link[0].DomainName
GUID = $Link[0].GUID
Linked = $IsLinked
LinksCount = $Link.Count
LinksEnabledCount = $EnabledLinks[0].Count
LinksDisabledCount = $EnabledLinks[1].Count
Links = $Link.Target
LinksObjects = $Link
}
$SummaryHashtable[$Key] = $SummaryLink
}
if ($AsHashTable -and $Summary) {
$SummaryHashtable
} elseif ($AsHashTable) {
$HashTable
} elseif ($Summary) {
$SummaryHashtable.Values
}
} else {
Get-GPOPrivInheritanceLoop @getGPOPrivInheritanceLoopSplat
}
}
End {
}
}
+175
View File
@@ -0,0 +1,175 @@
function Get-GPOZaurrLinkLoop {
[cmdletBinding()]
param(
[Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
[System.Collections.IDictionary] $CacheReturnedGPOs,
[System.Collections.IDictionary] $ForestInformation,
[validateset('All', 'Root', 'DomainControllers', 'Site', 'OrganizationalUnit')][string[]] $Linked,
[string] $SearchBase,
[Microsoft.ActiveDirectory.Management.ADSearchScope] $SearchScope,
[string] $Filter,
[switch] $SkipDuplicates,
[string[]] $Site
)
if (-not $ADObject) {
if ($Site) {
foreach ($S in $Site) {
foreach ($Domain in $ForestInformation.Domains) {
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for site $Site"
# Sites are defined only in primary domain
if ($ForestInformation['DomainsExtended'][$Domain]['DNSRoot'] -eq $ForestInformation['DomainsExtended'][$Domain]['Forest']) {
$Splat = @{
#Filter = $Filter
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
# Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
}
$Splat['Filter'] = "(objectClass -eq 'site') -and (name -eq '$S')"
$Splat['SearchBase'] = -join ("CN=Configuration,", $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName'])
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
if ($ADObjectGPO) {
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
}
}
}
}
} elseif ($SearchBase -or $SearchScope -or $Filter) {
foreach ($Domain in $ForestInformation.Domains) {
if (-not $Filter) {
$Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
}
$Splat = @{
Filter = $Filter
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
}
if ($PSBoundParameters.ContainsKey('SearchBase')) {
$DomainDistinguishedName = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
$SearchBaseDC = ConvertFrom-DistinguishedName -DistinguishedName $SearchBase -ToDC
if ($SearchBaseDC -ne $DomainDistinguishedName) {
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
continue
}
$Splat['SearchBase'] = $SearchBase
}
if ($PSBoundParameters.ContainsKey('SearchScope')) {
$Splat['SearchScope'] = $SearchScope
}
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
if ($ADObjectGPO) {
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
}
}
} elseif (-not $Filter) {
# if not linked, we force it to All
if (-not $Linked) {
$Linked = 'All'
}
foreach ($Domain in $ForestInformation.Domains) {
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for domain $Domain"
$Splat = @{
#Filter = $Filter
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
# Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
}
if ($Linked -contains 'Root' -or $Linked -contains 'All') {
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for domain $Domain at ROOT level"
$Splat['Filter'] = "objectClass -eq 'domainDNS'"
$Splat['SearchBase'] = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
if ($ADObjectGPO) {
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
}
}
if ($Linked -contains 'Site' -or $Linked -contains 'All') {
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for domain $Domain at SITE level"
# Sites are defined only in primary domain
if ($ForestInformation['DomainsExtended'][$Domain]['DNSRoot'] -eq $ForestInformation['DomainsExtended'][$Domain]['Forest']) {
$Splat['Filter'] = "(objectClass -eq 'site')"
$Splat['SearchBase'] = -join ("CN=Configuration,", $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName'])
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
if ($ADObjectGPO) {
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
}
}
}
if ($Linked -contains 'DomainControllers' -or $Linked -contains 'All') {
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for domain $Domain at DC level"
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
$Splat['SearchBase'] = $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
if ($ADObjectGPO) {
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
}
}
if ($Linked -contains 'OrganizationalUnit' -or $Linked -contains 'All') {
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for domain $Domain at OU level"
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
$Splat['SearchBase'] = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
if ($ADObjectGPO) {
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -SkipDomainRoot -SkipDomainControllers -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
}
}
}
}
<#
elseif ($Filter) {
foreach ($Domain in $ForestInformation.Domains) {
$Splat = @{
Filter = $Filter
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
}
if ($PSBoundParameters.ContainsKey('SearchBase')) {
$DomainDistinguishedName = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
$SearchBaseDC = ConvertFrom-DistinguishedName -DistinguishedName $SearchBase -ToDC
if ($SearchBaseDC -ne $DomainDistinguishedName) {
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
continue
}
$Splat['SearchBase'] = $SearchBase
}
if ($PSBoundParameters.ContainsKey('SearchScope')) {
$Splat['SearchScope'] = $SearchScope
}
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
if ($ADObjectGPO) {
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
}
}
}
#>
} else {
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObject -Domain '' -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
}
}
+61 -60
View File
@@ -6,69 +6,70 @@
[System.Collections.IDictionary] $GPOCache
)
if ($Object.GpLink -and $Object.GpLink.Trim() -ne '') {
#$Object.GpLink -split { $_ -eq '[' -or $_ -eq ']' } -replace ';0' -replace 'LDAP://'
$Object.GpLink -split '\[LDAP://' -split ';' | ForEach-Object -Process {
#Write-Verbose $_
if ($_.Length -gt 10) {
$DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDomainCN
$Output = [ordered] @{
DistinguishedName = $Object.DistinguishedName
CanonicalName = if ($Object.CanonicalName) { $Object.CanonicalName.TrimEnd('/') } else { $Object.CanonicalName }
Guid = [Regex]::Match( $_, '(?={)(.*)(?<=})').Value -replace '{' -replace '}'
}
$Search = -join ($DomainCN, $Output['Guid'])
if ($GPOCache -and -not $Limited) {
if ($GPOCache[$Search]) {
$Output['DisplayName'] = $GPOCache[$Search].DisplayName
$Output['DomainName'] = $GPOCache[$Search].DomainName
$Output['Owner'] = $GPOCache[$Search].Owner
$Output['GpoStatus'] = $GPOCache[$Search].GpoStatus
$Output['Description'] = $GPOCache[$Search].Description
$Output['CreationTime'] = $GPOCache[$Search].CreationTime
$Output['ModificationTime'] = $GPOCache[$Search].ModificationTime
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC
$Output['GPODistinguishedName'] = $_
[PSCustomObject] $Output
} else {
Write-Warning "Get-PrivGPOZaurrLink - Couldn't find link $Search in a GPO Cache. Lack of permissions for given GPO? Are you running as admin? Skipping."
}
} else {
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC
$Output['GPODistinguishedName'] = $_
[PSCustomObject] $Output
}
}
}
$ObjectsToProcess = $Object.GpLink -split '\]\['
} elseif ($Object.LinkedGroupPolicyObjects -and $Object.LinkedGroupPolicyObjects.Trim() -ne '') {
$Object.LinkedGroupPolicyObjects -split '\[LDAP://' -split ';' | ForEach-Object -Process {
if ($_.Length -gt 10) {
$DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDomainCN
$Output = [ordered] @{
DistinguishedName = $Object.DistinguishedName
CanonicalName = if ($Object.CanonicalName) { $Object.CanonicalName.TrimEnd('/') } else { $Object.CanonicalName }
Guid = [Regex]::Match( $_, '(?={)(.*)(?<=})').Value -replace '{' -replace '}'
}
$Search = -join ($DomainCN, $Output['Guid'])
if ($GPOCache -and -not $Limited) {
if ($GPOCache[$Search]) {
$Output['Name'] = $GPOCache[$Search].DisplayName
$Output['DomainName'] = $GPOCache[$Search].DomainName
$Output['Owner'] = $GPOCache[$Search].Owner
$Output['GpoStatus'] = $GPOCache[$Search].GpoStatus
$Output['Description'] = $GPOCache[$Search].Description
$Output['CreationTime'] = $GPOCache[$Search].CreationTime
$Output['ModificationTime'] = $GPOCache[$Search].ModificationTime
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC
$Output['GPODistinguishedName'] = $_
[PSCustomObject] $Output
} else {
Write-Warning "Get-PrivGPOZaurrLink - Couldn't find link $Search in a GPO Cache. Lack of permissions for given GPO? Are you running as admin? Skipping."
}
$ObjectsToProcess = $Object.LinkedGroupPolicyObjects -split '\]\['
} else {
$ObjectsToProcess = $null
}
$ObjectsToProcess | ForEach-Object -Process {
$Link = $_ -replace 'LDAP://' -replace '\]' -replace '\['
if ($Link.Length -gt 10) {
$SplitGPLink = $Link -split ';'
$DN = $SplitGPLink[0]
$Option = $SplitGPLink[1]
if ($Option -eq '0') {
$Enforced = $false
$Enabled = $true
} elseif ($Option -eq '1') {
$Enabled = $false
$Enforced = $false
} elseif ($Option -eq '2') {
$Enabled = $true
$Enforced = $true
} elseif ($Option -eq '3') {
$Enabled = $false
$Enforced = $true
} else {
if ($Object.GpLink) {
Write-Warning "Get-PrivGPOZaurrLink - This should't happen. Please investigate - Option: $Option"
} else {
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC
$Output['GPODistinguishedName'] = $_
[PSCustomObject] $Output
Write-Warning "Get-PrivGPOZaurrLink - Property GPLink is required to be able to tell if Enabled/Enforced is added. Skipping those settings."
}
$Enabled = $null
$Enforced = $null
}
$DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $DN -ToDomainCN
$Output = [ordered] @{
DistinguishedName = $Object.DistinguishedName
CanonicalName = if ($Object.CanonicalName) { $Object.CanonicalName.TrimEnd('/') } else { $Object.CanonicalName }
Guid = [Regex]::Match($DN, '(?={)(.*)(?<=})').Value -replace '{' -replace '}'
Enforced = $Enforced
Enabled = $Enabled
ObjectClass = $Object.ObjectClass
}
$Search = -join ($DomainCN, $Output['Guid'])
if ($GPOCache -and -not $Limited) {
if ($GPOCache[$Search]) {
$Output['DisplayName'] = $GPOCache[$Search].DisplayName
$Output['DomainName'] = $GPOCache[$Search].DomainName
$Output['Owner'] = $GPOCache[$Search].Owner
$Output['GpoStatus'] = $GPOCache[$Search].GpoStatus
$Output['Description'] = $GPOCache[$Search].Description
$Output['CreationTime'] = $GPOCache[$Search].CreationTime
$Output['ModificationTime'] = $GPOCache[$Search].ModificationTime
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $DN -ToDC
$Output['GPODistinguishedName'] = $DN
# This is object name, usually used for sites
$Output['Name'] = $Object.Name
[PSCustomObject] $Output
} else {
Write-Warning "Get-PrivGPOZaurrLink - Couldn't find link $Search in a GPO Cache. Lack of permissions for given GPO? Are you running as admin? Skipping."
}
} else {
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $DN -ToDC
$Output['GPODistinguishedName'] = $DN
[PSCustomObject] $Output
}
}
}
+55 -31
View File
@@ -9,25 +9,63 @@
[string] $Splitter = [System.Environment]::NewLine,
[switch] $ReturnObject,
[System.Collections.IDictionary] $ExcludeGroupPolicies,
[string[]] $Type
[string[]] $Type,
[System.Collections.IDictionary] $LinksSummaryCache
)
if ($XMLContent.GPO.LinksTo) {
$LinkSplit = ([Array] $XMLContent.GPO.LinksTo).Where( { $_.Enabled -eq $true }, 'Split')
[Array] $LinksEnabled = $LinkSplit[0]
[Array] $LinksDisabled = $LinkSplit[1]
$LinksEnabledCount = $LinksEnabled.Count
$LinksDisabledCount = $LinksDisabled.Count
$LinksTotalCount = ([Array] $XMLContent.GPO.LinksTo).Count
if ($LinksEnabledCount -eq 0) {
$Linked = $false
if ($LinksSummaryCache) {
$SearchGUID = -join ($XMLContent.GPO.Identifier.Domain.'#text', $XMLContent.GPO.Identifier.Identifier.InnerText -replace '{' -replace '}')
if ($LinksSummaryCache[$SearchGUID]) {
$Linked = $LinksSummaryCache[$SearchGUID].Linked
$LinksEnabledCount = $LinksSummaryCache[$SearchGUID].LinksEnabledCount
$LinksDisabledCount = $LinksSummaryCache[$SearchGUID].LinksDisabledCount
$LinksTotalCount = $LinksSummaryCache[$SearchGUID].LinksCount
$Links = $LinksSummaryCache[$SearchGUID].Links
$LinksObjects = $LinksSummaryCache[$SearchGUID].LinksObjects
} else {
$Linked = $true
$Linked = $false
$LinksEnabledCount = 0
$LinksDisabledCount = 0
$LinksTotalCount = 0
$Links = $null
$LinksObjects = $null
}
} else {
$Linked = $false
$LinksEnabledCount = 0
$LinksDisabledCount = 0
$LinksTotalCount = 0
if ($XMLContent.GPO.LinksTo) {
$LinkSplit = ([Array] $XMLContent.GPO.LinksTo).Where( { $_.Enabled -eq $true }, 'Split')
[Array] $LinksEnabled = $LinkSplit[0]
[Array] $LinksDisabled = $LinkSplit[1]
$LinksEnabledCount = $LinksEnabled.Count
$LinksDisabledCount = $LinksDisabled.Count
$LinksTotalCount = ([Array] $XMLContent.GPO.LinksTo).Count
if ($LinksEnabledCount -eq 0) {
$Linked = $false
} else {
$Linked = $true
}
$Links = @(
$XMLContent.GPO.LinksTo | ForEach-Object -Process {
if ($_) {
$_.SOMPath
}
}
) -join $Splitter
$LinksObjects = $XMLContent.GPO.LinksTo | ForEach-Object -Process {
if ($_) {
[PSCustomObject] @{
CanonicalName = $_.SOMPath
Enabled = $_.Enabled
NoOverride = $_.NoOverride
}
}
}
} else {
$Linked = $false
$LinksEnabledCount = 0
$LinksDisabledCount = 0
$LinksTotalCount = 0
$Links = $null
$LinksObjects = $null
}
}
# Find proper values for enabled/disabled user/computer settings
if ($XMLContent.GPO.Computer.Enabled -eq 'False') {
@@ -281,22 +319,8 @@
}
)
'Auditing' = if ($XMLContent.GPO.SecurityDescriptor.AuditingPresent.'#text' -eq 'true') { $true } else { $false }
'Links' = @(
$XMLContent.GPO.LinksTo | ForEach-Object -Process {
if ($_) {
$_.SOMPath
}
}
) -join $Splitter
'LinksObjects' = $XMLContent.GPO.LinksTo | ForEach-Object -Process {
if ($_) {
[PSCustomObject] @{
CanonicalName = $_.SOMPath
Enabled = $_.Enabled
NoOverride = $_.NoOverride
}
}
}
'Links' = $Links
'LinksObjects' = $LinksObjects
'GPOObject' = $GPO
}
if ($GPOOutput.ACL) {
+29
View File
@@ -0,0 +1,29 @@
$GPOZaurrLinks = [ordered] @{
Name = 'Group Policy Links'
Enabled = $true
ActionRequired = $null
Data = $null
Execute = {
Get-GPOZaurrLink -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -Summary
}
Processing = {
}
Variables = @{
}
Overview = {
}
Solution = {
New-HTMLTable -DataTable $Script:Reporting['GPOLinks']['Data'] -Filtering
if ($Script:Reporting['GPOLinks']['WarningsAndErrors']) {
New-HTMLSection -Name 'Warnings & Errors to Review' {
New-HTMLTable -DataTable $Script:Reporting['GPOLinks']['WarningsAndErrors'] -Filtering {
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
}
}
}
}
}
+1
View File
@@ -4,6 +4,7 @@
GPOConsistency = $GPOZaurrConsistency
GPODuplicates = $GPOZaurrDuplicates
GPOList = $GPOZaurrList
GPOLinks = $GPOZaurrLinks
GPOPassword = $GPOZaurrPassword
GPOPermissions = $GPOZaurrPermissionsAnalysis
GPOPermissionsAdministrative = $GPOZaurrPermissionsAdministrative
+5 -1
View File
@@ -47,6 +47,10 @@
if ($OwnerOnly -or $PermissionsOnly -and $Type) {
Write-Warning "Get-GPOZaurr - Using PermissionOnly or OwnerOnly with Type is not supported. "
}
if (-not $GPOPath) {
# This is needed, because Get-GPOReport doesn't deliver full scope of links, just some of it. It doesn't cover OUs with blocked inheritance, sites or crosslinked
$LinksSummaryCache = Get-GPOZaurrLink -AsHashTable -Summary -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
}
}
Process {
if (-not $GPOPath) {
@@ -86,7 +90,7 @@
Write-Warning "Get-GPOZaurr - Failed to get [$($GPO.DomainName)]($Count/$($GroupPolicies.Count)) $($GPO.DisplayName) GPOReport: $($_.Exception.Message). Skipping."
continue
}
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $GPO -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups -ReturnObject:$ReturnObject.IsPresent -ExcludeGroupPolicies $ExcludeGPO -Type $Type
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $GPO -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups -ReturnObject:$ReturnObject.IsPresent -ExcludeGroupPolicies $ExcludeGPO -Type $Type -LinksSummaryCache $LinksSummaryCache
} else {
$GPO
}
+104 -166
View File
@@ -1,13 +1,15 @@
function Get-GPOZaurrLink {
[cmdletbinding()]
[cmdletbinding(DefaultParameterSetName = 'Linked')]
param(
[parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
# weirdly enough site doesn't really work this way unless you give it 'CN=Configuration,DC=ad,DC=evotec,DC=xyz' as SearchBase
[parameter(ParameterSetName = 'Filter')][string] $Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')",
# site doesn't really work this way unless you give it 'CN=Configuration,DC=ad,DC=evotec,DC=xyz' as SearchBase
[parameter(ParameterSetName = 'Filter')][string] $Filter, # "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
[parameter(ParameterSetName = 'Filter')][string] $SearchBase,
[parameter(ParameterSetName = 'Filter')][Microsoft.ActiveDirectory.Management.ADSearchScope] $SearchScope,
[parameter(ParameterSetName = 'Linked', Mandatory)][validateset('Root', 'DomainControllers', 'Site', 'Other')][string] $Linked,
[parameter(ParameterSetName = 'Linked')][validateset('All', 'Root', 'DomainControllers', 'Site', 'OrganizationalUnit')][string[]] $Linked,
[parameter(ParameterSetName = 'Site')][string[]] $Site,
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
@@ -19,30 +21,47 @@
[parameter(ParameterSetName = 'Linked')]
[switch] $SkipDuplicates,
[parameter(ParameterSetName = 'Site')]
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[System.Collections.IDictionary] $GPOCache,
[parameter(ParameterSetName = 'Site')]
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[alias('ForestName')][string] $Forest,
[parameter(ParameterSetName = 'Site')]
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[string[]] $ExcludeDomains,
[parameter(ParameterSetName = 'Site')]
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
[parameter(ParameterSetName = 'Site')]
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[System.Collections.IDictionary] $ExtendedForestInformation
[System.Collections.IDictionary] $ExtendedForestInformation,
[parameter(ParameterSetName = 'Site')]
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[switch] $AsHashTable,
[parameter(ParameterSetName = 'Site')]
[parameter(ParameterSetName = 'Filter')]
[parameter(ParameterSetName = 'ADObject')]
[parameter(ParameterSetName = 'Linked')]
[switch] $Summary
)
Begin {
$CacheReturnedGPOs = [ordered] @{}
@@ -52,6 +71,7 @@
# While initially we used $ForestInformation.Domains but the thing is GPOs can be linked to other domains so we need to get them all so we can use cache of it later on even if we're processing just one domain
# That's why we use $ForestInformation.Forest.Domains instead
foreach ($Domain in $ForestInformation.Forest.Domains) {
Write-Verbose "Get-GPOZaurrLink - Building GPO cache for domain $Domain"
$QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
Get-GPO -All -DomainName $Domain -Server $QueryServer | ForEach-Object {
$GPOCache["$Domain$($_.ID.Guid)"] = $_
@@ -60,173 +80,91 @@
}
}
Process {
if (-not $ADObject) {
if ($Linked) {
foreach ($Domain in $ForestInformation.Domains) {
$Splat = @{
#Filter = $Filter
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
# Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
$getGPOLoopSplat = @{
Linked = $Linked
ForestInformation = $ForestInformation
SearchScope = $SearchScope
SearchBase = $SearchBase
ADObject = $ADObject
Filter = $Filter
SkipDuplicates = $SkipDuplicates
Site = $Site
}
Remove-EmptyValue -Hashtable $getGPOLoopSplat -Recursive
$getGPOLoopSplat['CacheReturnedGPOs'] = $CacheReturnedGPOs
if ($AsHashTable -or $Summary) {
$HashTable = [ordered] @{}
$SummaryHashtable = [ordered] @{}
$Links = Get-GPOZaurrLinkLoop @getGPOLoopSplat
foreach ($Link in $Links) {
$Key = -join ($Link.DomainName, $Link.GUID)
if (-not $HashTable[$Key]) {
$HashTable[$Key] = [System.Collections.Generic.List[PSCustomObject]]::new()
}
$HashTable[$Key].Add($Link)
}
foreach ($Key in $HashTable.Keys) {
[Array] $Link = $HashTable[$Key]
$EnabledLinks = $Link.Enabled.Where( { $_ -eq $true }, 'split')
$LinkedRoot = $false
$LinkedRootPlaces = [System.Collections.Generic.List[string]]::new()
$LinkedSite = $false
$LinkedSitePlaces = [System.Collections.Generic.List[string]]::new()
$LinkedOU = $false
$LinkedCrossDomain = $false
$LinkedCrossDomainPlaces = [System.Collections.Generic.List[string]]::new()
foreach ($InternalLink in $Link) {
if ($InternalLink.ObjectClass -eq 'domainDNS') {
$LinkedRoot = $true
$LinkedRootPlaces.Add($InternalLink.DistinguishedName)
} elseif ($InternalLink.ObjectClass -eq 'site') {
$LinkedSite = $true
$LinkedSitePlaces.Add($InternalLink.Name)
} else {
$LinkedOU = $true
}
if ($Linked -contains 'DomainControllers') {
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']
#if ($SearchBase -notlike "*$DomainDistinguishedName") {
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
# continue
#}
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
$Splat['SearchBase'] = $SearchBase
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
foreach ($_ in $ADObjectGPO) {
$OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache
foreach ($OutputGPO in $OutputGPOs) {
if (-not $SkipDuplicates) {
$OutputGPO
} else {
$UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid)
if (-not $CacheReturnedGPOs[$UniqueGuid]) {
$CacheReturnedGPOs[$UniqueGuid] = $OutputGPO
$OutputGPO
}
}
}
}
}
if ($Linked -contains 'Root') {
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
#if ($SearchBase -notlike "*$DomainDistinguishedName") {
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
# continue
# }
$Splat['Filter'] = "objectClass -eq 'domainDNS'"
$Splat['SearchBase'] = $SearchBase
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
foreach ($_ in $ADObjectGPO) {
$OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache
foreach ($OutputGPO in $OutputGPOs) {
if (-not $SkipDuplicates) {
$OutputGPO
} else {
$UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid)
if (-not $CacheReturnedGPOs[$UniqueGuid]) {
$CacheReturnedGPOs[$UniqueGuid] = $OutputGPO
$OutputGPO
}
}
}
}
}
if ($Linked -contains 'Site') {
# Sites are defined only in primary domain
if ($ForestInformation['DomainsExtended'][$Domain]['DNSRoot'] -eq $ForestInformation['DomainsExtended'][$Domain]['Forest']) {
$SearchBase = -join ("CN=Configuration,", $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName'])
# if ($SearchBase -notlike "*$DomainDistinguishedName") {
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
#continue
#}
$Splat['Filter'] = "(objectClass -eq 'site')"
$Splat['SearchBase'] = $SearchBase
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
foreach ($_ in $ADObjectGPO) {
Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache
}
}
}
if ($Linked -contains 'Other') {
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
#if ($SearchBase -notlike "*$DomainDistinguishedName") {
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
# continue
#}
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
$Splat['SearchBase'] = $SearchBase
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
foreach ($_ in $ADObjectGPO) {
if ($_.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']) {
# other skips Domain Root
} elseif ($_.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']) {
# other skips Domain Controllers
} else {
$OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache
foreach ($OutputGPO in $OutputGPOs) {
if (-not $SkipDuplicates) {
$OutputGPO
} else {
$UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid)
if (-not $CacheReturnedGPOs[$UniqueGuid]) {
$CacheReturnedGPOs[$UniqueGuid] = $OutputGPO
$OutputGPO
}
}
}
}
}
$CN = ConvertFrom-DistinguishedName -ToDomainCN -DistinguishedName $InternalLink.distinguishedName
$GPOCN = ConvertFrom-DistinguishedName -ToDomainCN -DistinguishedName $InternalLink.GPODomainDistinguishedName
if ($CN -ne $GPOCN) {
$LinkedCrossDomain = $true
$LinkedCrossDomainPlaces.Add($InternalLink.DistinguishedName)
}
}
} else {
foreach ($Domain in $ForestInformation.Domains) {
$Splat = @{
Filter = $Filter
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
}
if ($PSBoundParameters.ContainsKey('SearchBase')) {
$DomainDistinguishedName = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
$SearchBaseDC = ConvertFrom-DistinguishedName -DistinguishedName $SearchBase -ToDC
if ($SearchBaseDC -ne $DomainDistinguishedName) {
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
continue
}
$Splat['SearchBase'] = $SearchBase
}
if ($PSBoundParameters.ContainsKey('SearchScope')) {
$Splat['SearchScope'] = $SearchScope
}
try {
$ADObjectGPO = Get-ADObject @Splat
} catch {
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
}
foreach ($_ in $ADObjectGPO) {
$OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache
foreach ($OutputGPO in $OutputGPOs) {
if (-not $SkipDuplicates) {
$OutputGPO
} else {
$UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid)
if (-not $CacheReturnedGPOs[$UniqueGuid]) {
$CacheReturnedGPOs[$UniqueGuid] = $OutputGPO
$OutputGPO
}
}
}
}
if ($EnabledLinks[0].Count -gt 0) {
$IsLinked = $true
} else {
$IsLinked = $false
}
$SummaryLink = [PSCustomObject] @{
DisplayName = $Link[0].DisplayName
DomainName = $Link[0].DomainName
GUID = $Link[0].GUID
Linked = $IsLinked
LinksCount = $Link.Count
LinksEnabledCount = $EnabledLinks[0].Count
LinksDisabledCount = $EnabledLinks[1].Count
LinkedCrossDomain = $LinkedCrossDomain
LinkedRoot = $LinkedRoot
LinkedSite = $LinkedSite
LinkedOU = $LinkedOU
LinkedSitePlaces = $LinkedSitePlaces
LinkedRootPlaces = $LinkedRootPlaces
LinkedCrossDomainPlaces = $LinkedCrossDomainPlaces
Links = $Link.DistinguishedName
LinksObjects = $Link
}
$SummaryHashtable[$Key] = $SummaryLink
}
if ($AsHashTable -and $Summary) {
$SummaryHashtable
} elseif ($AsHashTable) {
$HashTable
} elseif ($Summary) {
$SummaryHashtable.Values
}
} else {
foreach ($Object in $ADObject) {
Get-PrivGPOZaurrLink -Object $Object -Limited:$Limited.IsPresent -GPOCache $GPOCache
}
Get-GPOZaurrLinkLoop @getGPOLoopSplat
}
}
End {
+1 -1
View File
@@ -13,7 +13,7 @@
$CacheSummaryLinks = [ordered] @{} # cache
# Get all links
$Links = Get-GPOZaurrLink -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
$Links = Get-GPOZaurrLink -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation -Linked Root, DomainControllers, Other
foreach ($Link in $Links) {
if (-not $CacheSummaryLinks["$($Link.DomainName)$($Link.Guid)"]) {
$CacheSummaryLinks["$($Link.DomainName)$($Link.Guid)"] = [System.Collections.Generic.List[System.Object]]::new()
+1 -1
View File
@@ -21,7 +21,7 @@
[parameter(ParameterSetName = 'Level', Mandatory)][int] $Limit,
# ParameterSet4
[parameter(ParameterSetName = 'Linked', Mandatory)][validateset('Root', 'DomainControllers', 'Site', 'Other')][string] $Linked,
[parameter(ParameterSetName = 'Linked', Mandatory)][validateset('Root', 'DomainControllers', 'Site', 'OrganizationalUnit')][string] $Linked,
# ParameterSet5
[parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
+10
View File
@@ -57,6 +57,16 @@ That's it. Whenever there's a new version, you run the command, and you can enjo
## Changelog
- 0.0.102 - 2021.01.02
- [x] Improved `Get-GPOZaurrLink`
- [x] Supports all links across forest
- [x] Renamed Linked validate set from `Other` to `OrganizationalUnit`
- [x] Improved `Get-GPOZaurrLinkSummary`
- [x] Improved/BugFix `Get-GPOZaurr` to properly detect linked GPOs in sites/cross-domain
- [x] Improved `Invoke-GPOZaurrPermission`
- [x] Renamed Linked validate set from `Other` to `OrganizationalUnit`
- [x] Improved `Invoke-GPOZaurr`
- [x] Added `GPOLinks` basic list
- 0.0.101 - 23.12.2020
- [x] Improved `Get-GPOZaurrBroken`
- [x] It now detects `ObjectClass Issue`