mirror of
https://github.com/EvotecIT/GPOZaurr.git
synced 2026-07-26 20:00:09 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 06c711694e | |||
| 8a38ac4556 | |||
| 9d2ae288c0 | |||
| 0bc50328ee | |||
| a74b662c9b | |||
| 37d8db92f7 | |||
| d094344f9f |
+1
-1
@@ -8,7 +8,7 @@
|
||||
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-GPOZaurrBrokenLink', '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-GPOZaurrBrokenLink', '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.103'
|
||||
ModuleVersion = '0.0.105'
|
||||
PowerShellVersion = '5.1'
|
||||
PrivateData = @{
|
||||
PSData = @{
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
$DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $DN -ToDomainCN
|
||||
$Output = [ordered] @{
|
||||
DistinguishedName = $Object.DistinguishedName
|
||||
#Domain = ConvertFrom-DistinguishedName -DistinguishedName $Object.DistinguishedName -ToDomainCN
|
||||
CanonicalName = if ($Object.CanonicalName) { $Object.CanonicalName.TrimEnd('/') } else { $Object.CanonicalName }
|
||||
Guid = [Regex]::Match($DN, '(?={)(.*)(?<=})').Value -replace '{' -replace '}'
|
||||
Enforced = $Enforced
|
||||
|
||||
@@ -42,6 +42,8 @@ $GPOZaurrBrokenLink = [ordered] @{
|
||||
"When GPO is deleted in a proper way it usually is removed from AD, SYSVOL and any link to it is also discarded. "
|
||||
"Unfortunetly this is true only if the GPO is created and linked within same domain. "
|
||||
"If GPO is linked in another domain, this leaves a broken link hanging on wherever it was linked before. "
|
||||
"Additionally Remove-GPO cmdlet doesn't handle site link deletions, which causes dead links to be stuck on sites until those are manually deleted. "
|
||||
"This means that any GPOs deleted using PowerShell may leave trail. "
|
||||
}
|
||||
New-HTMLText -Text @(
|
||||
'As it stands currently there are ',
|
||||
@@ -49,14 +51,15 @@ $GPOZaurrBrokenLink = [ordered] @{
|
||||
' broken links that need to be deleted over '
|
||||
$Script:Reporting['GPOBrokenLink']['Variables']['UniqueObjects'].Count,
|
||||
' unique objects. '
|
||||
|
||||
) -FontSize 10pt -FontWeight normal, bold, normal, bold, normal
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOBrokenLink']['Variables']['WillFixPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOBrokenLink']['Variables']['WillFixPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
) -FontSize 10pt -FontWeight normal, bold, normal, bold, normal -LineBreak
|
||||
if ($Script:Reporting['GPOBrokenLink']['Data'].Count -ne 0) {
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOBrokenLink']['Variables']['WillFixPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOBrokenLink']['Variables']['WillFixPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
}
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
|
||||
@@ -1,4 +1,32 @@
|
||||
function Get-GPOZaurrBrokenLink {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Finds any GPO link that doesn't have a matching GPO (already removed GPO).
|
||||
|
||||
.DESCRIPTION
|
||||
Finds any GPO link that doesn't have a matching GPO (already removed GPO).
|
||||
|
||||
.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 ExtendedForestInformation
|
||||
Ability to provide Forest Information from another command to speed up processing
|
||||
|
||||
.EXAMPLE
|
||||
Get-GPOZaurrBrokenLink -Verbose | Format-Table -AutoSize *
|
||||
|
||||
.EXAMPLE
|
||||
Get-GPOZaurrBrokenLink -Verbose -IncludeDomains ad.evotec.pl | Format-Table -AutoSize *
|
||||
|
||||
.NOTES
|
||||
General notes
|
||||
#>
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[alias('ForestName')][string] $Forest,
|
||||
@@ -6,14 +34,22 @@ function Get-GPOZaurrBrokenLink {
|
||||
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation
|
||||
)
|
||||
$ErrorFound = $false
|
||||
$PoliciesAD = @{}
|
||||
$ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExcludeDomainControllers $ExcludeDomainControllers -IncludeDomainControllers $IncludeDomainControllers -SkipRODC:$SkipRODC -ExtendedForestInformation $ExtendedForestInformation -Extended
|
||||
# We need to request all GPOS from Forest. Requesting just for any domain won't be enough
|
||||
$ForestInformation = Get-WinADForestDetails -Forest $Forest -Extended # -Extended
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
$QueryServer = $ForestInformation['QueryServers']["$Domain"].HostName[0]
|
||||
$SystemsContainer = $ForestInformation['DomainsExtended'][$Domain].SystemsContainer
|
||||
if ($SystemsContainer) {
|
||||
$PoliciesSearchBase = -join ("CN=Policies,", $SystemsContainer)
|
||||
$PoliciesInAD = Get-ADObject -SearchBase $PoliciesSearchBase -SearchScope OneLevel -Filter * -Server $QueryServer -Properties Name, gPCFileSysPath, DisplayName, DistinguishedName, Description, Created, Modified, ObjectClass, ObjectGUID
|
||||
try {
|
||||
$PoliciesInAD = Get-ADObject -ErrorAction Stop -SearchBase $PoliciesSearchBase -SearchScope OneLevel -Filter * -Server $QueryServer -Properties Name, gPCFileSysPath, DisplayName, DistinguishedName, Description, Created, Modified, ObjectClass, ObjectGUID
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrBrokenLink - An error occured while searching $PoliciesSearchBase. Error $($_.Exception.Message). Please resolve this before continuing."
|
||||
$ErrorFound = $true
|
||||
break
|
||||
}
|
||||
foreach ($Policy in $PoliciesInAD) {
|
||||
$GUIDFromDN = ConvertFrom-DistinguishedName -DistinguishedName $Policy.DistinguishedName
|
||||
# $Key = "$($Domain)$($GuidFromDN)"
|
||||
@@ -34,6 +70,12 @@ function Get-GPOZaurrBrokenLink {
|
||||
Write-Warning "Get-GPOZaurrBroken - Couldn't get GPOs from $Domain. Skipping"
|
||||
}
|
||||
}
|
||||
if ($ErrorFound) {
|
||||
return
|
||||
}
|
||||
# In case of links we can request here whatever user requested.
|
||||
# This will search for broken links in domain user requested
|
||||
$ForestInformation = Get-WinADForestDetails -Forest $Forest -Extended -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
$Links = Get-GPOZaurrLinkLoop -Linked 'All' -ForestInformation $ForestInformation
|
||||
foreach ($Link in $Links) {
|
||||
if (-not $PoliciesAD[$Link.GPODistinguishedName]) {
|
||||
|
||||
@@ -1,4 +1,35 @@
|
||||
function Repair-GPOZaurrBrokenLink {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Removes any link to GPO that no longer exists.
|
||||
|
||||
.DESCRIPTION
|
||||
Removes any link to GPO that no longer exists. It scans all site, organizational unit or domain root making sure every single link that may be linking to GPO that doesn't exists anymore is gone.
|
||||
|
||||
.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 ExtendedForestInformation
|
||||
Ability to provide Forest Information from another command to speed up processing
|
||||
|
||||
.PARAMETER LimitProcessing
|
||||
Allows to specify maximum number of items that will be fixed in a single run. It doesn't affect amount of GPOs processed
|
||||
|
||||
.EXAMPLE
|
||||
Repair-GPOZaurrBrokenLink -Verbose -LimitProcessing 1 -WhatIf
|
||||
|
||||
.EXAMPLE
|
||||
Repair-GPOZaurrBrokenLink -Verbose -IncludeDomains ad.evotec.pl -LimitProcessing 1 -WhatIf
|
||||
|
||||
.NOTES
|
||||
General notes
|
||||
#>
|
||||
[cmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[alias('ForestName')][string] $Forest,
|
||||
@@ -7,7 +38,7 @@ function Repair-GPOZaurrBrokenLink {
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation,
|
||||
[int] $LimitProcessing
|
||||
)
|
||||
$ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation -Extended
|
||||
$ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -Extended
|
||||
$Links = Get-GPOZaurrBrokenLink -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ForestInformation
|
||||
$Cache = @{}
|
||||
foreach ($Link in $Links) {
|
||||
@@ -38,14 +69,22 @@ function Repair-GPOZaurrBrokenLink {
|
||||
Write-Verbose "Repair-GPOZaurrBrokenLink - preparing for removal link to $GPODN ($Key)"
|
||||
}
|
||||
}
|
||||
#
|
||||
if ($Found) {
|
||||
$NewGpLink = $($FixedLinks -join '')
|
||||
try {
|
||||
Write-Verbose "Repair-GPOZaurrBrokenLink - setting gpLink to $Key - $NewGPLink"
|
||||
Set-ADObject -Identity $Key -Server $Server -Replace @{ gPLink = $NewGpLink } -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Warning "Repair-GPOZaurrBrokenLink - couldn't replace gpLink at $Key with $NewGpLink"
|
||||
if ($NewGpLink) {
|
||||
try {
|
||||
Write-Verbose "Repair-GPOZaurrBrokenLink - setting gpLink to $Key - $NewGPLink"
|
||||
Set-ADObject -Identity $Key -Server $Server -Replace @{ gPLink = $NewGpLink } -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Warning "Repair-GPOZaurrBrokenLink - setting gpLink to $Key - $NewGpLink failed! Error $($_.Exception.Message)"
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Write-Verbose "Repair-GPOZaurrBrokenLink - clearing gpLink for $Key (no other links)"
|
||||
Set-ADObject -Identity $Key -Server $Server -Clear gPLink -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Warning "Repair-GPOZaurrBrokenLink - clearing gpLink for $Key failed! Error $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
if ($LimitProcessing -eq $Count) {
|
||||
break
|
||||
|
||||
@@ -1,4 +1,35 @@
|
||||
function Repair-GPOZaurrNetLogonOwner {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sets new owner to each file in NetLogon share.
|
||||
|
||||
.DESCRIPTION
|
||||
Sets new owner to each file in NetLogon share.
|
||||
|
||||
.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 ExtendedForestInformation
|
||||
Ability to provide Forest Information from another command to speed up processing
|
||||
|
||||
.PARAMETER Principal
|
||||
Provide named owner. If not provided default S-1-5-32-544 is used.
|
||||
|
||||
.PARAMETER LimitProcessing
|
||||
Allows to specify maximum number of items that will be fixed in a single run. It doesn't affect amount of GPOs processed
|
||||
|
||||
.EXAMPLE
|
||||
Repair-GPOZaurrNetLogonOwner -WhatIf -Verbose -IncludeDomains ad.evotec.pl
|
||||
|
||||
.NOTES
|
||||
General notes
|
||||
#>
|
||||
[cmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[alias('ForestName')][string] $Forest,
|
||||
|
||||
@@ -57,6 +57,14 @@ That's it. Whenever there's a new version, you run the command, and you can enjo
|
||||
|
||||
## Changelog
|
||||
|
||||
- 0.0.105 - 2021.01.05
|
||||
- [x] Improved `Get-GPOZaurr`
|
||||
- [x] Improved report `GPOBrokenLink`
|
||||
- 0.0.104 - 2021.01.04
|
||||
- [x] Improved `Get-GPOZaurrBrokenLink`
|
||||
- [x] Improved `Repair-GPOZaurrBrokenLink`
|
||||
- [x] Improved `Get-GPOZaurr`
|
||||
- [x] Improved report `GPOBrokenLink`
|
||||
- 0.0.103 - 2021.01.04
|
||||
- [x] Improved `Get-GPOZaurr`
|
||||
- [x] Added new report `GPOBrokenLink`
|
||||
|
||||
Reference in New Issue
Block a user