From 8db961cba636a008139dea051c05170821db8b1f Mon Sep 17 00:00:00 2001 From: Przemyslaw Klys Date: Thu, 5 Aug 2021 22:08:46 +0200 Subject: [PATCH] Improve report --- Private/Invoke.GPOZaurrOrganizationalUnit.ps1 | 103 +++--------------- 1 file changed, 16 insertions(+), 87 deletions(-) diff --git a/Private/Invoke.GPOZaurrOrganizationalUnit.ps1 b/Private/Invoke.GPOZaurrOrganizationalUnit.ps1 index 70462ef..7b98804 100644 --- a/Private/Invoke.GPOZaurrOrganizationalUnit.ps1 +++ b/Private/Invoke.GPOZaurrOrganizationalUnit.ps1 @@ -11,7 +11,7 @@ $Script:Reporting['GPOOrganizationalUnit']['Variables']['RequiresDiffFixPerDomain'] = @{} $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'] = @{} foreach ($OU in $Script:Reporting['GPOOrganizationalUnit']['Data']) { - + $Script:Reporting['GPOOrganizationalUnit']['Variables']['TotalOU']++ # Create Per Domain Variables if (-not $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$OU.DomainName]) { $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$OU.DomainName] = 0 @@ -33,37 +33,6 @@ $Script:Reporting['GPOOrganizationalUnit']['Variables']['Legitimate']++ } - - <# - # Checks - if ($OU.GPOCount -eq 0 -and $OU.ObjectCount -eq 0) { - $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithoutObjectsAndGPOs']++ - $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFix']++ - $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$OU.DomainName]++ - } elseif ($OU.GPOCount -gt 0 -and $OU.ObjectCount -eq 0) { - $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithGPOsAndNoObjects']++ - $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFix']++ - $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$OU.DomainName]++ - } elseif ($OU.GPOCount -gt 0 -and $OU.ObjectCount -gt 0) { - $ObjectsFound = $false - foreach ($ObjectClass in $OU.ObjectClasses) { - if ($ObjectClass -in @('user', 'computer')) { - $ObjectsFound = $true - } - } - if ($ObjectsFound) { - $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithBoth']++ - } else { - $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithGPOsAndNoProperObjects']++ - $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFix']++ - } - } elseif ($OU.GPOCount -eq 0 -and $OU.ObjectCount -gt 0) { - $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithObjectsAndNoGPO']++ - } else { - $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithBoth']++ - } - - #> } if ($Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFix'] -gt 0) { $Script:Reporting['GPOOrganizationalUnit']['ActionRequired'] = $true @@ -72,6 +41,7 @@ } } Variables = @{ + TotalOU = 0 UnlinkGPO = 0 UnlinkGPODeleteOU = 0 DeleteOU = 0 @@ -87,17 +57,9 @@ "In most Active Directories there are a lot of Organizational Units that have different use cases to store different type of objects. " "As Active Directories change over time you can often find Organizational Units with linked GPOs and no objects inside. " "In some cases thats's expected, but in some cases it's totally unnessecary, and for very large AD can be a problem. " + "Additionally only User and Computer objects can have GPO applied to them, so having GPO applied to a any other object type won't really work. " ) - - New-HTMLText -Text "Here's a short summary of ", "Organizational Units", ": " -FontSize 10pt -FontWeight normal, bold, normal - New-HTMLList -Type Unordered { - New-HTMLListItem -Text 'Organizational Units without any Objects and Group Policies: ', $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithoutObjectsAndGPOs'] -FontWeight normal, bold - New-HTMLListItem -Text 'Organizational Units with Group Policies, but without any objects: ', $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithGPOsAndNoObjects'] -FontWeight normal, bold - New-HTMLListItem -Text 'Organizational Units with Group Policies, but without computer/user objects: ', $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithGPOsAndNoProperObjects'] -FontWeight normal, bold - New-HTMLListItem -Text "Organizational Units with Group Policies and with objects: ", $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithBoth'] -FontWeight normal, bold - New-HTMLListItem -Text "Organizational Units with Objects, but no directly linked Group Policies: ", $Script:Reporting['GPOOrganizationalUnit']['Variables']['OUWithObjectsAndNoGPO'] -FontWeight normal, bold - } -FontSize 10pt - New-HTMLText -FontSize 10pt -Text "Following will need to happen: " -FontWeight bold + New-HTMLText -FontSize 10pt -Text "Following can happen: " -FontWeight bold New-HTMLList -Type Unordered { New-HTMLListItem -Text 'Organizational Units that can have Group Policies unlinked (objects exists): ', $Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPO'] -FontWeight normal, bold New-HTMLListItem -Text 'Organizational Units that can have Group Policies unlinked and OU removed (be careful!) (no objects): ', $Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPODeleteOU'] -FontWeight normal, bold @@ -109,6 +71,10 @@ New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal } } -FontSize 10pt + New-HTMLText -Text @( + "Please make sure that you really want to unlink GPO or delete Organizational Unit before executing changes. Sometimes it's completly valid to keep one or the other. " + "Unlinking GPO from OU that has no Computer or User objects is fairly safe exercise. Removing OU requires a bit more dive in, and should only be executed if you know what you're doing. " + ) -FontWeight normal, bold -Color None, Red -FontSize 10pt } Solution = { New-HTMLSection -Invisible { @@ -130,6 +96,7 @@ New-HTMLTable -DataTable $Script:Reporting['GPOOrganizationalUnit']['Data'] -Filtering { #New-HTMLTableCondition -Name 'IsOwnerConsistent' -Value $false -BackgroundColor Salmon -ComparisonType string -Row #New-HTMLTableCondition -Name 'IsOwnerAdministrative' -Value $false -BackgroundColor Salmon -ComparisonType string -Row + New-TableHeader -ResponsiveOperations none -Names 'GPONames', 'Objects' New-HTMLTableCondition -Name 'Status' -ComparisonType string -Value 'Unlink GPO, Delete OU' -BackgroundColor Salmon -Row New-HTMLTableCondition -Name 'Status' -ComparisonType string -Value 'Unlink GPO' -BackgroundColor YellowOrange -Row New-HTMLTableCondition -Name 'Status' -ComparisonType string -Value 'Delete OU' -BackgroundColor Red -Row @@ -141,7 +108,7 @@ New-HTMLTableCondition -Name 'Level' -Value 'Child' -ComparisonType string -Operator eq } -HighlightHeaders 'GPOCount', 'ObjectCount' -BackgroundColor Salmon -FailBackgroundColor LightGreen #> - } -PagingOptions 10, 20, 30, 40, 50 -SearchBuilder + } -PagingOptions 10, 20, 30, 40, 50 -SearchBuilder -ExcludeProperty GPO } if ($Script:Reporting['Settings']['HideSteps'] -eq $false) { New-HTMLSection -Name 'Steps to fix Group Organizational Units' { @@ -157,9 +124,8 @@ } -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 fixing Group Policy Owners. To generate new report please use:" + New-HTMLText -Text "Depending when this report was run you may want to prepare new report before proceeding with unlinking unused Group Policies. To generate new report please use:" New-HTMLCodeBlock -Code { Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrGPOOrganizationalUnitBefore.html -Verbose -Type GPOOrganizationalUnit } @@ -169,53 +135,16 @@ } New-HTMLText -Text "Alternatively if you prefer working with console you can run: " New-HTMLCodeBlock -Code { - $OwnersGPO = Get-GPOZaurrOwner -IncludeSysvol -Verbose + $OwnersGPO = Get-GPOZaurrOrganizationalUnit -Verbose $OwnersGPO | 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 of fixing GPO Owner does NOT touch GPO content. It simply changes owners on AD and SYSVOL at the same time. " - "However, it's always good to have a backup before executing changes that may impact Active Directory. " - } - 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 'Unlink unused Group Policies' { + } - New-HTMLWizardStep -Name 'Set GPO Owners to Administrative (Domain Admins)' { - New-HTMLText -Text "Following command will find any GPO which doesn't have proper GPO Owner (be it due to inconsistency or not being Domain Admin) and will enforce new GPO Owner. " - New-HTMLText -Text "Make sure when running it for the first time to run it with ", "WhatIf", " parameter as shown below to prevent accidental removal." -FontWeight normal, bold, normal -Color Black, Red, Black - New-HTMLCodeBlock -Code { - Set-GPOZaurrOwner -Type All -Verbose -WhatIf - } - 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 { - Set-GPOZaurrOwner -Type All -Verbose -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor' - } - 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 changed matches expected data." - } -LineBreak - New-HTMLText -Text "Once happy with results please follow with command (this will start fixing process): " -LineBreak -FontWeight bold - New-HTMLCodeBlock -Code { - Set-GPOZaurrOwner -Type All -Verbose -LimitProcessing 2 - } - 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 { - Set-GPOZaurrOwner -Type All -Verbose -LimitProcessing 2 -IncludeDomains 'YourDomainYouHavePermissionsFor' - } - New-HTMLText -TextBlock { - "This command when executed sets new owner only on first X non-compliant GPO Owners for AD/SYSVOL. Use LimitProcessing parameter to prevent mass change 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. " - } + New-HTMLWizardStep -Name 'Delete unused Organizational Units' { + } New-HTMLWizardStep -Name 'Verification report' { New-HTMLText -TextBlock {