Files
GPOZaurr/Private/Invoke.GPOZaurrOrphans.ps1
T
2021-08-10 21:05:13 +02:00

320 lines
26 KiB
PowerShell

$GPOZaurrOrphans = [ordered] @{
Name = 'Broken Group Policies'
Enabled = $true
ActionRequired = $null
Data = $null
Execute = {
Get-GPOZaurrBroken -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
}
Processing = {
$Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'] = @{}
$Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssuePerDomain'] = @{}
$Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssuePerDomain'] = @{}
foreach ($GPO in $Script:Reporting['GPOBroken']['Data']) {
if (-not $Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]) {
$Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName] = 0
}
if (-not $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssuePerDomain'][$GPO.DomainName]) {
$Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssuePerDomain'][$GPO.DomainName] = 0
}
if (-not $Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssuePerDomain'][$GPO.DomainName]) {
$Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssuePerDomain'][$GPO.DomainName] = 0
}
if ($GPO.Status -eq 'Not available in AD') {
$Script:Reporting['GPOBroken']['Variables']['NotAvailableInAD']++
$Script:Reporting['GPOBroken']['Variables']['ToBeDeleted']++
$Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]++
} elseif ($GPO.Status -eq 'Not available on SYSVOL') {
$Script:Reporting['GPOBroken']['Variables']['NotAvailableOnSysvol']++
$Script:Reporting['GPOBroken']['Variables']['ToBeDeleted']++
$Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]++
} elseif ($GPO.Status -eq 'Permissions issue') {
$Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue']++
$Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssuePerDomain'][$GPO.DomainName]++
} elseif ($GPO.Status -eq 'ObjectClass issue') {
$Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssue']++
$Script:Reporting['GPOBroken']['Variables']['ToBeDeleted']++
$Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssuePerDomain'][$GPO.DomainName]++
$Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]++
}
}
if ($Script:Reporting['GPOBroken']['Variables']['ToBeDeleted'] -gt 0) {
$Script:Reporting['GPOBroken']['ActionRequired'] = $true
} else {
$Script:Reporting['GPOBroken']['ActionRequired'] = $false
}
}
Variables = @{
NotAvailableInAD = 0
NotAvailableOnSysvol = 0
NotAvailablePermissionIssue = 0
NotAvailablePermissionIssuePerDomain = $null
ToBeDeleted = 0
ToBeDeletedPerDomain = $null
NotAvailableObjectClassIssue = 0
NotAvailableObjectClassIssuePerDomain = $null
}
Overview = {
<#
New-HTMLPanel {
New-HTMLText -TextBlock {
"Group Policies are stored in two places - Active Directory (metadata) and SYSVOL (content)."
"Since those are managed in different ways, replicated in different ways it's possible because of different issues they get out of sync."
} -LineBreak
New-HTMLText -Text "For example:"
New-HTMLList -Type Unordered {
New-HTMLListItem -Text 'USN Rollback in AD could cause group policies to reappar in Active Directory, yet SYSVOL data would be unavailable'
New-HTMLListItem -Text 'Group Policy deletion failing to delete GPO content'
New-HTMLListItem -Text 'DFSR replication failing between DCs'
}
New-HTMLText -Text 'Following chart presents ', 'Broken / Orphaned Group Policies' -FontSize 10pt -FontWeight normal, bold
New-HTMLList -Type Unordered {
New-HTMLListItem -Text 'Group Policies on SYSVOL, but no details in AD: ', $Script:Reporting['GPOBroken']['Variables']['NotAvailableInAD'] -FontWeight normal, bold
New-HTMLListItem -Text 'Group Policies in AD, but no content on SYSVOL: ', $Script:Reporting['GPOBroken']['Variables']['NotAvailableOnSysvol'] -FontWeight normal, bold
New-HTMLListItem -Text "Group Policies which couldn't be assed due to permissions issue: ", $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue'] -FontWeight normal, bold
} -FontSize 10pt
New-HTMLText -FontSize 10pt -Text 'Those problems must be resolved before doing other clenaup activities.'
New-HTMLChart {
New-ChartBarOptions -Type barStacked
New-ChartLegend -Name 'Not in AD', 'Not on SYSVOL', 'Permissions Issue' -Color Crimson, LightCoral, IndianRed
New-ChartBar -Name 'Orphans' -Value $Script:Reporting['GPOBroken']['Variables']['NotAvailableInAD'], $Script:Reporting['GPOBroken']['Variables']['NotAvailableOnSysvol'], $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue']
} -Title 'Broken / Orphaned Group Policies' -TitleAlignment center
}
#>
}
Summary = {
New-HTMLText -TextBlock {
"Group Policies are stored in two places - Active Directory (metadata) and SYSVOL (content)."
"Since those are managed in different ways, replicated in different ways it's possible because of different issues they get out of sync."
} -FontSize 10pt -LineBreak
New-HTMLText -Text "For example:" -FontSize 10pt -FontWeight bold
New-HTMLList -Type Unordered {
New-HTMLListItem -Text 'USN Rollback in AD could cause already deleted Group Policies to reapper in Active Directory, yet SYSVOL data would be unavailable'
New-HTMLListItem -Text 'Group Policy deletion failing to delete GPO content'
New-HTMLListItem -Text 'Permission issue preventing deletion of GPO content'
New-HTMLListItem -Text 'Failing DFSR replication between DCs'
} -FontSize 10pt
New-HTMLText -Text 'Following problems were detected:' -FontSize 10pt -FontWeight bold
New-HTMLList -Type Unordered {
New-HTMLListItem -Text 'Group Policies on SYSVOL, but no details in AD: ', $Script:Reporting['GPOBroken']['Variables']['NotAvailableInAD'] -FontWeight normal, bold
New-HTMLListItem -Text 'Group Policies in AD, but no content on SYSVOL: ', $Script:Reporting['GPOBroken']['Variables']['NotAvailableOnSysvol'] -FontWeight normal, bold
New-HTMLListItem -Text 'Group Policies which exists, but have wrong ObjectClass: ', $Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssue'] -FontWeight normal, bold
New-HTMLListItem -Text "Group Policies which couldn't be assessed due to permissions issue: ", $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue'] -FontWeight normal, bold
} -FontSize 10pt
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
New-HTMLList -Type Unordered {
foreach ($Domain in $Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'].Keys) {
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
}
} -FontSize 10pt
New-HTMLText -Text "Please review output in table and follow the steps below table to get Active Directory Group Policies in healthy state." -FontSize 10pt
}
Solution = {
New-HTMLSection -Invisible {
New-HTMLPanel {
& $Script:GPOConfiguration['GPOBroken']['Summary']
}
New-HTMLPanel {
New-HTMLChart {
New-ChartBarOptions -Type barStacked
New-ChartLegend -Name 'Not in AD', 'Not on SYSVOL', 'ObjectClass Issue', 'Permissions Issue' -Color Crimson, LightCoral, MediumOrchid, IndianRed
New-ChartBar -Name 'Broken' -Value $Script:Reporting['GPOBroken']['Variables']['NotAvailableInAD'], $Script:Reporting['GPOBroken']['Variables']['NotAvailableOnSysvol'], $Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssue'], $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue']
} -Title 'Broken / Orphaned Group Policies' -TitleAlignment center
}
}
New-HTMLSection -Name 'Health State of Group Policies' {
New-HTMLTable -DataTable $Script:Reporting['GPOBroken']['Data'] -Filtering {
New-HTMLTableCondition -Name 'Status' -Value "Not available in AD" -BackgroundColor Salmon -ComparisonType string
New-HTMLTableCondition -Name 'Status' -Value "Not available on SYSVOL" -BackgroundColor LightCoral -ComparisonType string
New-HTMLTableCondition -Name 'Status' -Value "ObjectClass issue" -BackgroundColor MediumOrchid -ComparisonType string
New-HTMLTableCondition -Name 'Status' -Value "Permissions issue" -BackgroundColor MediumVioletRed -ComparisonType string -Color White
} -PagingOptions 10, 20, 30, 40, 50
}
if ($Script:Reporting['Settings']['HideSteps'] -eq $false) {
New-HTMLSection -Name 'Steps to fix - Not available on SYSVOL / Active Directory / ObjectClass issue' {
New-HTMLContainer {
New-HTMLSpanStyle -FontSize 10pt {
New-HTMLWizard {
New-HTMLWizardStep -Name 'Prepare environment' {
New-HTMLText -Text "To be able to execute actions in automated way please install required modules. Those modules will be installed straight from Microsoft PowerShell Gallery."
New-HTMLCodeBlock -Code {
Install-Module GPOZaurr -Force
Import-Module GPOZaurr -Force
} -Style powershell
New-HTMLText -Text "Using force makes sure newest version is downloaded from PowerShellGallery regardless of what is currently installed. Once installed you're ready for next step."
}
New-HTMLWizardStep -Name 'Prepare report' {
New-HTMLText -Text "Depending when this report was run you may want to prepare new report before proceeding with removal. To generate new report please use:"
New-HTMLCodeBlock -Code {
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrBrokenGpoBefore.html -Verbose -Type GPOBroken
}
New-HTMLText -TextBlock {
"When executed it will take a while to generate all data and provide you with new report depending on size of environment."
"Once confirmed that data is still showing issues and requires fixing please proceed with next step."
}
New-HTMLText -Text "Alternatively if you prefer working with console you can run: "
New-HTMLCodeBlock -Code {
$GPOOutput = Get-GPOZaurrBroken -Verbose
$GPOOutput | Format-Table
}
New-HTMLText -Text "It provides same data as you see in table above just doesn't prettify it for you."
}
New-HTMLWizardStep -Name 'Make a backup (optional)' {
New-HTMLText -TextBlock {
"The process fixing broken GPOs will delete AD or SYSVOL content depending on type of a problem. "
"While it's always useful to have a backup, this backup won't actually backup those broken group policies"
" for a simple reason that those are not backupable. You can't back up GPO if there is no SYSVOL content"
" and you can't backup GPO if there's only SYSVOL content. "
"However, since the script does make changes to GPOs it's advised to have a backup anyways! "
}
New-HTMLCodeBlock -Code {
$GPOSummary = Backup-GPOZaurr -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -Type All
$GPOSummary | Format-Table # only if you want to display output of backup
}
New-HTMLText -TextBlock {
"Above command when executed will make a backup to Desktop, create GPO folder and within it it will put all those GPOs. "
}
}
New-HTMLWizardStep -Name 'Fix GPOs not available in AD' {
New-HTMLText -Text @(
"Following command when executed runs cleanup procedure that removes all broken GPOs on SYSVOL side. ",
"Make sure when running it for the first time to run it with ",
"WhatIf ",
"parameter as shown below to prevent accidental removal. ",
'When run it will remove any GPO remains from SYSVOL, that should not be there, as AD metadata is already gone.'
"Please notice I'm using SYSVOL as a type, because the removal will happen on SYSVOL. "
) -FontWeight normal, normal, bold, normal -Color Black, Black, Red, Black
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type SYSVOL -WhatIf -Verbose
}
New-HTMLText -TextBlock {
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
}
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type SYSVOL -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor' -Verbose
}
New-HTMLText -TextBlock {
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be deleted matches expected data. "
"Keep in mind that what backup command does is simply copy SYSVOL content to given place. "
"Since there is no GPO metadata in AD there's no real restore process for this step. "
"It's there to make sure if someone kept some data in there and wants to get access to it, he/she can. "
} -LineBreak
New-HTMLText -Text "Once happy with results please follow with command (this will start deletion process): " -LineBreak -FontWeight bold
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type SYSVOL -LimitProcessing 2 -BackupPath $Env:UserProfile\Desktop\GPOSYSVOLBackup -Verbose
}
New-HTMLText -TextBlock {
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
}
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type SYSVOL -LimitProcessing 2 -BackupPath $Env:UserProfile\Desktop\GPOSYSVOLBackup -IncludeDomains 'YourDomainYouHavePermissionsFor' -Verbose
}
New-HTMLText -TextBlock {
"This command when executed deletes only first X broken GPOs. Use LimitProcessing parameter to prevent mass delete and increase the counter when no errors occur. "
"Repeat step above as much as needed increasing LimitProcessing count till there's nothing left. In case of any issues please review and action accordingly. "
"If there's nothing else to be deleted on SYSVOL side, we can skip to next step step. "
}
}
New-HTMLWizardStep -Name 'Fix GPOs not available on SYSVOL' {
New-HTMLText -Text @(
"Following command when executed runs cleanup procedure that removes all broken GPOs on Active Directory side."
"Make sure when running it for the first time to run it with ",
"WhatIf",
" parameter as shown below to prevent accidental removal."
'When run it will remove any GPO remains from AD, that should not be there, as SYSVOL content is already gone.'
"Please notice I'm using AD as a type, because the removal will happen on AD side. "
) -FontWeight normal, normal, bold, normal -Color Black, Black, Red, Black
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type AD -WhatIf -Verbose
}
New-HTMLText -TextBlock {
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
}
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type AD -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor' -Verbose
}
New-HTMLText -TextBlock {
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be deleted matches expected data. "
"Keep in mind that there is no backup for this. "
"Since there is no SYSVOL data, and only AD object is there there's no real restore process for this step. "
"Once you delete it, it's gone. "
} -LineBreak
New-HTMLText -Text 'Once happy with results please follow with command (this will start deletion process): ' -LineBreak -FontWeight bold
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type AD -LimitProcessing 2 -Verbose
}
New-HTMLText -TextBlock {
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
}
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type AD -LimitProcessing 2 -IncludeDomains 'YourDomainYouHavePermissionsFor' -Verbose
}
New-HTMLText -TextBlock {
"This command when executed deletes only first X broken GPOs. Use LimitProcessing parameter to prevent mass delete and increase the counter when no errors occur. "
"Repeat step above as much as needed increasing LimitProcessing count till there's nothing left. In case of any issues please review and action accordingly. "
"If there's nothing else to be deleted on AD side, we can skip to next step step. "
}
}
New-HTMLWizardStep -Name 'Fix GPOs of wrong ObjectClass' {
New-HTMLText -Text @(
"Following command when executed runs cleanup procedure that removes all GPOs which have ObjectClass of Container, rather than required groupPolicyContainer. "
"Make sure when running it for the first time to run it with ",
"WhatIf",
" parameter as shown below to prevent accidental removal."
'When run it will remove GPO metadata from AD, and any files/folders from SYSVOL.'
) -FontWeight normal, normal, bold, normal -Color Black, Black, Red, Black
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type ObjectClass -WhatIf -Verbose
}
New-HTMLText -TextBlock {
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
}
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type ObjectClass -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor' -Verbose
}
New-HTMLText -TextBlock {
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be deleted matches expected data. "
"Keep in mind that there is no backup for this as backup process doesn't see GPOs that are of wrong ObjectClass. "
"Once you delete it, it's gone. "
} -LineBreak
New-HTMLText -Text 'Once happy with results please follow with command (this will start deletion process): ' -LineBreak -FontWeight bold
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type ObjectClass -LimitProcessing 2 -Verbose
}
New-HTMLText -TextBlock {
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
}
New-HTMLCodeBlock -Code {
Remove-GPOZaurrBroken -Type ObjectClass -LimitProcessing 2 -IncludeDomains 'YourDomainYouHavePermissionsFor' -Verbose
}
New-HTMLText -TextBlock {
"This command when executed deletes only first X broken GPOs. Use LimitProcessing parameter to prevent mass delete and increase the counter when no errors occur. "
"Repeat step above as much as needed increasing LimitProcessing count till there's nothing left. In case of any issues please review and action accordingly. "
"If there's nothing else to be deleted, we can skip to next step step. "
}
}
New-HTMLWizardStep -Name 'Verification report' {
New-HTMLText -TextBlock {
"Once cleanup task was executed properly, we need to verify that report now shows no problems."
}
New-HTMLCodeBlock -Code {
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrBrokenGpoAfter.html -Verbose -Type GPOBroken
}
New-HTMLText -Text "If everything is healthy in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
}
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
}
}
}
}
if ($Script:Reporting['GPOBroken']['WarningsAndErrors']) {
New-HTMLSection -Name 'Warnings & Errors to Review' {
New-HTMLTable -DataTable $Script:Reporting['GPOBroken']['WarningsAndErrors'] -Filtering {
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
}
}
}
}
}