mirror of
https://github.com/EvotecIT/GPOZaurr.git
synced 2026-07-26 11:49:17 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0da051a53b | |||
| f5fb9e2dee | |||
| 9784370c77 | |||
| 83363bb843 | |||
| 6c2e774b10 | |||
| b70cccf0db | |||
| 1788615711 | |||
| 0a863de36b | |||
| 31dd7e31a6 | |||
| 46a927b92d | |||
| 3e5c5fd6fb | |||
| 2a92c90b0c | |||
| 0f8fbb1220 | |||
| c37dd91403 | |||
| bc55cd09c5 | |||
| 2331e449b1 | |||
| d27760931e | |||
| 64bc1ff092 | |||
| 6f92043c3a | |||
| 7ce5027abd | |||
| 0c8e23f6af | |||
| 731ba420b9 | |||
| 8790be18bb | |||
| e495411714 | |||
| fab33b8d14 | |||
| e00c93b798 | |||
| ee5e03d666 | |||
| ad2067c714 | |||
| b5e4fd07dc | |||
| 981e71483a | |||
| 26e9486894 | |||
| 2f874b8dc8 | |||
| f1e211e560 | |||
| 4d82b51577 |
@@ -1,19 +0,0 @@
|
||||
#Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Verbose -Type NetLogon, GPOOrphans, GPOList, GPOConsistency
|
||||
|
||||
# Working conditions
|
||||
#Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurrOrphans.html -Verbose -Type GPOOrphans
|
||||
#Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurrEmptyUnlinked.html -Verbose -Type GPOList
|
||||
#Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurrEmptyUnlinked.html -Verbose -Type GPOConsistency
|
||||
#Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Verbose -Type NetLogon
|
||||
|
||||
#Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Verbose -Type GPOOwners
|
||||
|
||||
#Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Verbose -Type GPOPermissionsRoot
|
||||
|
||||
#Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Verbose -Type GPOOrphans, GPOConsistency, GPOList, GPOPermissionsRoot, NetLogon, GPOFiles
|
||||
#Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Verbose -Type GPOConsistency
|
||||
#Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Verbose -Type GPOOrphans, GPOConsistency
|
||||
#Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Verbose -Type GPOList
|
||||
#Optimize-HTML -File 'C:\Support\GitHub\GpoZaurr\Examples\Reports\GPOZaurr.html' -OutputFile 'C:\Support\GitHub\GpoZaurr\Examples\Reports\GPOZaurr-Minified.html'
|
||||
@@ -0,0 +1,7 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$Output = Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type GPOList -PassThru
|
||||
$Output
|
||||
|
||||
Write-Color -Text 'Output of nested report' -Color DarkYellow -LinesBefore 1 -LinesAfter 1
|
||||
$Output.GPOList
|
||||
@@ -0,0 +1,3 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type NetLogonPermissions, GPOOrphans, GPOList, GPOConsistency, GPOOwners, GPODuplicates
|
||||
@@ -1 +0,0 @@
|
||||
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Verbose -Type NetLogon, GPOOrphans, GPOList, GPOConsistency,GPOOwners
|
||||
@@ -0,0 +1,15 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$Types = @(
|
||||
@{ Name = 'GPOOwners'; Path = "$PSScriptRoot\Reports\GPOOwners.html" }
|
||||
@{ 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 = 'GPOPassword'; Path = "$PSScriptRoot\Reports\GPOPassword.html" }
|
||||
@{ Name = 'NetLogonPermissions'; Path = "$PSScriptRoot\Reports\NetLogonPermissions.html" }
|
||||
)
|
||||
|
||||
foreach ($Type in $Types) {
|
||||
Invoke-GPOZaurr -FilePath $Type.Path -Type $Type.Name -HideHTML
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Get-GPOZaurrPassword -GPOPath 'C:\Users\przemyslaw.klys\Desktop\GPOExport_2020.10.12'
|
||||
@@ -0,0 +1,2 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
+5
-5
@@ -6,9 +6,9 @@
|
||||
CompatiblePSEditions = @('Desktop')
|
||||
Copyright = '(c) 2011 - 2020 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-GPOZaurrFiles', 'Get-GPOZaurrFilesPolicyDefinition', 'Get-GPOZaurrFolders', 'Get-GPOZaurrInheritance', 'Get-GPOZaurrLegacyFiles', 'Get-GPOZaurrLink', 'Get-GPOZaurrLinkSummary', 'Get-GPOZaurrNetLogon', 'Get-GPOZaurrOwner', 'Get-GPOZaurrPassword', 'Get-GPOZaurrPermission', 'Get-GPOZaurrPermissionConsistency', 'Get-GPOZaurrPermissionRoot', 'Get-GPOZaurrPermissionSummary', 'Get-GPOZaurrSysvolDFSR', 'Get-GPOZaurrWMI', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrContent', 'Invoke-GPOZaurrPermission', 'Invoke-GPOZaurrSupport', 'New-GPOZaurrWMI', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrBroken', 'Remove-GPOZaurrFolders', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrNetLogonOwner', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Set-GPOOwner', 'Set-GPOZaurrOwner')
|
||||
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-GPOZaurrPermissionConsistency', '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-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Set-GPOOwner', 'Set-GPOZaurrOwner')
|
||||
GUID = 'f7d4c9e4-0298-4f51-ad77-e8e3febebbde'
|
||||
ModuleVersion = '0.0.69'
|
||||
ModuleVersion = '0.0.76'
|
||||
PowerShellVersion = '5.1'
|
||||
PrivateData = @{
|
||||
PSData = @{
|
||||
@@ -18,15 +18,15 @@
|
||||
}
|
||||
}
|
||||
RequiredModules = @(@{
|
||||
ModuleVersion = '0.0.186'
|
||||
ModuleVersion = '0.0.187'
|
||||
ModuleName = 'PSSharedGoods'
|
||||
Guid = 'ee272aa8-baaa-4edf-9f45-b6d6f7d844fe'
|
||||
}, @{
|
||||
ModuleVersion = '0.0.100'
|
||||
ModuleVersion = '0.0.102'
|
||||
ModuleName = 'ADEssentials'
|
||||
Guid = '9fc9fd61-7f11-4f4b-a527-084086f1905f'
|
||||
}, @{
|
||||
ModuleVersion = '0.0.119'
|
||||
ModuleVersion = '0.0.120'
|
||||
ModuleName = 'PSWriteHTML'
|
||||
Guid = 'a7bdf640-f5cb-4acf-9de0-365b322d245c'
|
||||
}, 'CimCmdlets', 'Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Utility', 'Microsoft.PowerShell.Security')
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
function Find-GPOPassword {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[string] $Path
|
||||
)
|
||||
#Convert XML in a String file
|
||||
[string]$XMLString = Get-Content -LiteralPath $Path
|
||||
#Check if Cpassword Exist in the file
|
||||
if ($XMLString.Contains("cpassword")) {
|
||||
#Take the Cpassword Value from XML String file
|
||||
[string]$Cpassword = [regex]::matches($XMLString, '(cpassword=).+?(?=\")')
|
||||
$Cpassword = $Cpassword.split('(\")')[1]
|
||||
#Check if Cpassword has a value
|
||||
if ($Cpassword.Length -gt 20 -and $Cpassword -notlike '*cpassword*') {
|
||||
$Mod = ($Cpassword.length % 4)
|
||||
switch ($Mod) {
|
||||
'1' { $Cpassword = $Cpassword.Substring(0, $Cpassword.Length - 1) }
|
||||
'2' { $Cpassword += ('=' * (4 - $Mod)) }
|
||||
'3' { $Cpassword += ('=' * (4 - $Mod)) }
|
||||
}
|
||||
$Base64Decoded = [Convert]::FromBase64String($Cpassword)
|
||||
$AesObject = [System.Security.Cryptography.AesCryptoServiceProvider]::new()
|
||||
#Use th AES Key
|
||||
[Byte[]] $AesKey = @(0x4e, 0x99, 0x06, 0xe8, 0xfc, 0xb6, 0x6c, 0xc9, 0xfa, 0xf4, 0x93, 0x10, 0x62, 0x0f, 0xfe, 0xe8, 0xf4, 0x96, 0xe8, 0x06, 0xcc, 0x05, 0x79, 0x90, 0x20, 0x9b, 0x09, 0xa4, 0x33, 0xb6, 0x6c, 0x1b)
|
||||
$AesIV = New-Object Byte[]($AesObject.IV.Length)
|
||||
$AesObject.IV = $AesIV
|
||||
$AesObject.Key = $AesKey
|
||||
$DecryptorObject = $AesObject.CreateDecryptor()
|
||||
[Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)
|
||||
#Convert Hash variable in a String valute
|
||||
$Password = [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
|
||||
} else {
|
||||
$Password = ''
|
||||
}
|
||||
}
|
||||
$Password
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
function Get-GitHubVersion {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)][string] $Cmdlet,
|
||||
[Parameter(Mandatory)][string] $RepositoryOwner,
|
||||
[Parameter(Mandatory)][string] $RepositoryName
|
||||
)
|
||||
$App = Get-Command -Name $Cmdlet -ErrorAction SilentlyContinue
|
||||
if ($App) {
|
||||
[Array] $GitHubReleases = (Get-GitHubLatestRelease -Url "https://api.github.com/repos/$RepositoryOwner/$RepositoryName/releases" -Verbose:$false)
|
||||
$LatestVersion = $GitHubReleases[0]
|
||||
if (-not $LatestVersion.Errors) {
|
||||
if ($App.Version -eq $LatestVersion.Version) {
|
||||
"Current/Latest: $($LatestVersion.Version) at $($LatestVersion.PublishDate)"
|
||||
} elseif ($App.Version -lt $LatestVersion.Version) {
|
||||
"Current: $($App.Version), Published: $($LatestVersion.Version) at $($LatestVersion.PublishDate). Update?"
|
||||
} elseif ($App.Version -gt $LatestVersion.Version) {
|
||||
"Current: $($App.Version), Published: $($LatestVersion.Version) at $($LatestVersion.PublishDate). Lucky you!"
|
||||
}
|
||||
} else {
|
||||
"Current: $($App.Version)"
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
-3
@@ -6,7 +6,8 @@
|
||||
[switch] $PermissionsOnly,
|
||||
[switch] $OwnerOnly,
|
||||
[System.Collections.IDictionary] $ADAdministrativeGroups,
|
||||
[string] $Splitter = [System.Environment]::NewLine
|
||||
[string] $Splitter = [System.Environment]::NewLine,
|
||||
[switch] $ReturnObject
|
||||
)
|
||||
if ($XMLContent.GPO.LinksTo) {
|
||||
$LinkSplit = ([Array] $XMLContent.GPO.LinksTo).Where( { $_.Enabled -eq $true }, 'Split')
|
||||
@@ -54,6 +55,36 @@
|
||||
} elseif ($UserEnabled -eq $false -and $ComputerEnabled -eq $true) {
|
||||
$Enabled = 'User configuration settings disabled'
|
||||
}
|
||||
|
||||
$ComputerSettingsAvailable = if ($null -eq $XMLContent.GPO.Computer.ExtensionData) { $false } else { $true }
|
||||
$UserSettingsAvailable = if ($null -eq $XMLContent.GPO.User.ExtensionData) { $false } else { $true }
|
||||
|
||||
$ComputerProblem = $false
|
||||
if ($ComputerEnabled -eq $true -and $ComputerSettingsAvailable -eq $true) {
|
||||
$ComputerOptimized = $true
|
||||
} elseif ($ComputerEnabled -eq $true -and $ComputerSettingsAvailable -eq $false) {
|
||||
$ComputerOptimized = $false
|
||||
} elseif ($ComputerEnabled -eq $false -and $ComputerSettingsAvailable -eq $false) {
|
||||
$ComputerOptimized = $true
|
||||
} else {
|
||||
# Enabled $false, but ComputerData is there.
|
||||
$ComputerOptimized = $false
|
||||
$ComputerProblem = $true
|
||||
}
|
||||
|
||||
$UserProblem = $false
|
||||
if ($UserEnabled -eq $true -and $UserSettingsAvailable -eq $true) {
|
||||
$UserOptimized = $true
|
||||
} elseif ($UserEnabled -eq $true -and $UserSettingsAvailable -eq $false) {
|
||||
$UserOptimized = $false
|
||||
} elseif ($UserEnabled -eq $false -and $UserSettingsAvailable -eq $false) {
|
||||
$UserOptimized = $true
|
||||
} else {
|
||||
# Enabled $false, but UserData is there.
|
||||
$UserOptimized = $false
|
||||
$UserProblem = $true
|
||||
}
|
||||
|
||||
if (-not $PermissionsOnly) {
|
||||
if ($XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text') {
|
||||
$AdministrativeGroup = $ADAdministrativeGroups['ByNetBIOS']["$($XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text')"]
|
||||
@@ -123,9 +154,13 @@
|
||||
'LinksDisabledCount' = $LinksDisabledCount
|
||||
'Enabled' = $Enabled
|
||||
'ComputerEnabled' = $ComputerEnabled
|
||||
'ComputerOptimized' = $ComputerOptimized
|
||||
'ComputerProblem' = $ComputerProblem
|
||||
'UserEnabled' = $UserEnabled
|
||||
'ComputerSettingsAvailable' = if ($null -eq $XMLContent.GPO.Computer.ExtensionData) { $false } else { $true }
|
||||
'UserSettingsAvailable' = if ($null -eq $XMLContent.GPO.User.ExtensionData) { $false } else { $true }
|
||||
'UserOptimized' = $UserOptimized
|
||||
'UserProblem' = $UserProblem
|
||||
'ComputerSettingsAvailable' = $ComputerSettingsAvailable
|
||||
'UserSettingsAvailable' = $UserSettingsAvailable
|
||||
'ComputerSettingsStatus' = if ($XMLContent.GPO.Computer.VersionDirectory -eq 0 -and $XMLContent.GPO.Computer.VersionSysvol -eq 0) { "NeverModified" } else { "Modified" }
|
||||
'ComputerSetttingsVersionIdentical' = if ($XMLContent.GPO.Computer.VersionDirectory -eq $XMLContent.GPO.Computer.VersionSysvol) { $true } else { $false }
|
||||
'ComputerSettings' = $XMLContent.GPO.Computer.ExtensionData.Extension
|
||||
@@ -181,6 +216,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
'GPOObject' = $GPO
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
$GPOZaurrAnalysis = [ordered] @{
|
||||
Name = 'Group Policy Content'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Invoke-GPOZaurrContent
|
||||
}
|
||||
Processing = {
|
||||
|
||||
}
|
||||
Variables = @{
|
||||
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Solution = {
|
||||
foreach ($Key in $Script:Reporting['GPOAnalysis']['Data'].Keys) {
|
||||
New-HTMLTab -Name $Key {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOAnalysis']['Data'][$Key] -Filtering -Title $Key
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOAnalysis']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOAnalysis']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
$GPOZaurrBlockedInheritance = [ordered] @{
|
||||
Name = 'Group Policy Blocked Inhertiance'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrInheritance -IncludeBlockedObjects -OnlyBlockedInheritance
|
||||
}
|
||||
Processing = {
|
||||
|
||||
}
|
||||
Variables = @{
|
||||
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOBlockedInheritance']['Data'] -Filtering
|
||||
if ($Script:Reporting['GPOBlockedInheritance']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOBlockedInheritance']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
$GPOZaurrConsistency = [ordered] @{
|
||||
Name = 'GPO Permissions Consistency'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = { Get-GPOZaurrPermissionConsistency -Type All -VerifyInheritance }
|
||||
Processing = {
|
||||
foreach ($GPO in $Script:Reporting['GPOConsistency']['Data']) {
|
||||
if ($GPO.ACLConsistent -eq $true) {
|
||||
$Script:Reporting['GPOConsistency']['Variables']['Consistent']++
|
||||
} else {
|
||||
$Script:Reporting['GPOConsistency']['Variables']['Inconsistent']++
|
||||
}
|
||||
if ($GPO.ACLConsistentInside -eq $true) {
|
||||
$Script:Reporting['GPOConsistency']['Variables']['ConsistentInside']++
|
||||
} else {
|
||||
$Script:Reporting['GPOConsistency']['Variables']['InconsistentInside']++
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOConsistency']['Variables']['Inconsistent'].Count -gt 0 -or $Script:Reporting['GPOConsistency']['Variables']['InconsistentInside'].Count -gt 0 ) {
|
||||
$Script:Reporting['GPOConsistency']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPOConsistency']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = @{
|
||||
Consistent = 0
|
||||
Inconsistent = 0
|
||||
ConsistentInside = 0
|
||||
InconsistentInside = 0
|
||||
}
|
||||
Overview = {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -Text 'Following chart presents ', 'permissions consistency between Active Directory and SYSVOL for Group Policies' -FontSize 10pt -FontWeight normal, bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Top level permissions consistency: ', $Script:Reporting['GPOConsistency']['Variables']['Consistent'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Inherited permissions consistency: ', $Script:Reporting['GPOConsistency']['Variables']['ConsistentInside'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Inconsistent top level permissions: ', $Script:Reporting['GPOConsistency']['Variables']['Inconsistent'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Inconsistent inherited permissions: ", $Script:Reporting['GPOConsistency']['Variables']['InconsistentInside'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text 'Having incosistent permissions on AD in comparison to those on SYSVOL can lead to uncontrolled ability to modify them.'
|
||||
New-HTMLChart {
|
||||
New-ChartLegend -Names 'Bad', 'Good' -Color PaleGreen, Salmon
|
||||
New-ChartBarOptions -Type barStacked
|
||||
New-ChartLegend -Name 'Consistent', 'Inconsistent'
|
||||
New-ChartBar -Name 'TopLevel' -Value $Script:Reporting['GPOConsistency']['Variables']['Consistent'], $Script:Reporting['GPOConsistency']['Variables']['Inconsistent']
|
||||
New-ChartBar -Name 'Inherited' -Value $Script:Reporting['GPOConsistency']['Variables']['ConsistentInside'], $Script:Reporting['GPOConsistency']['Variables']['InconsistentInside']
|
||||
} -Title 'Permissions Consistency' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
Summary = {
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"When GPO is created it creates an entry in Active Directory (metadata) and SYSVOL (content). "
|
||||
"Two different places meens two different sets of permissions. Group Policy module is making sure the data in both places is correct. "
|
||||
"However, for different reasons it's not nessecary the case and often permissions go out of sync between AD and SYSVOL. "
|
||||
"This test verifies consistency of policies between AD and SYSVOL in two ways. "
|
||||
"It checks top level permissions for a GPO, and then checks if all files within said GPO are inheriting permissions or have different permissions in place. "
|
||||
}
|
||||
New-HTMLText -Text 'Following list presents ', 'permissions consistency between Active Directory and SYSVOL for Group Policies' -FontSize 10pt -FontWeight normal, bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Top level permissions consistency: ', $Script:Reporting['GPOConsistency']['Variables']['Consistent'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Inherited permissions consistency: ', $Script:Reporting['GPOConsistency']['Variables']['ConsistentInside'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Inconsistent top level permissions: ', $Script:Reporting['GPOConsistency']['Variables']['Inconsistent'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Inconsistent inherited permissions: ", $Script:Reporting['GPOConsistency']['Variables']['InconsistentInside'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text 'Having incosistent permissions on AD in comparison to those on SYSVOL can lead to uncontrolled ability to modify them. Please notice that if ', `
|
||||
' Not available ', 'is visible in the table you should first fix related, more pressing issue, before fixing permissions inconsistency.' -FontWeight normal, bold, normal
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
& $Script:GPOConfiguration['GPOConsistency']['Summary']
|
||||
}
|
||||
New-HTMLPanel {
|
||||
New-HTMLChart {
|
||||
# New-ChartLegend -Names 'Bad', 'Good' -Color PaleGreen, Salmon
|
||||
New-ChartBarOptions -Type barStacked
|
||||
New-ChartLegend -Name 'Consistent', 'Inconsistent'
|
||||
New-ChartBar -Name 'TopLevel' -Value $Script:Reporting['GPOConsistency']['Variables']['Consistent'], $Script:Reporting['GPOConsistency']['Variables']['Inconsistent']
|
||||
New-ChartBar -Name 'Inherited' -Value $Script:Reporting['GPOConsistency']['Variables']['ConsistentInside'], $Script:Reporting['GPOConsistency']['Variables']['InconsistentInside']
|
||||
} -Title 'Permissions Consistency' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policy Permissions Consistency' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOConsistency']['Data'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'ACLConsistent' -Value $false -BackgroundColor Salmon -TextTransform capitalize -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ACLConsistentInside' -Value $false -BackgroundColor Salmon -TextTransform capitalize -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ACLConsistent' -Value $true -BackgroundColor PaleGreen -TextTransform capitalize -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ACLConsistentInside' -Value $true -BackgroundColor PaleGreen -TextTransform capitalize -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ACLConsistent' -Value 'Not available' -BackgroundColor Crimson -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ACLConsistentInside' -Value 'Not available' -BackgroundColor Crimson -ComparisonType string
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
if ($Script:Reporting['GPOConsistency']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOConsistency']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Steps to fix - Permissions Consistency' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLText -Text 'Following steps will guide you how to fix permissions consistency'
|
||||
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 fixing permissions inconsistencies. To generate new report please use:"
|
||||
New-HTMLCodeBlock -Code {
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrPermissionsInconsistentBefore.html -Verbose -Type GPOConsistency
|
||||
}
|
||||
New-HTMLText -Text {
|
||||
"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-GPOZaurrPermissionConsistency
|
||||
$GPOOutput | Format-Table # do your actions as desired
|
||||
}
|
||||
New-HTMLText -Text "It provides same data as you see in table above just doesn't prettify it for you."
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Fix inconsistent permissions' {
|
||||
New-HTMLText -Text "Following command when executed fixes inconsistent permissions."
|
||||
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-HTMLText -Text "Make sure to fill in TargetDomain to match your Domain Admin permission account"
|
||||
|
||||
New-HTMLCodeBlock -Code {
|
||||
Repair-GPOZaurrPermissionConsistency -IncludeDomains "TargetDomain" -Verbose -WhatIf
|
||||
}
|
||||
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. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Repair-GPOZaurrPermissionConsistency -LimitProcessing 2 -IncludeDomains "TargetDomain"
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed repairs only first X inconsistent permissions. Use LimitProcessing parameter to prevent mass fixing 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-HTMLText -Text "If there's nothing else to be fixed, we can skip to next step step"
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Fix inconsistent downlevel permissions' {
|
||||
New-HTMLText -Text "Unfortunetly this step is manual until automation is developed. "
|
||||
New-HTMLText -Text "If there are inconsistent permissions found inside GPO one has to fix them manually by going into SYSVOL and making sure inheritance is enabled, and that permissions are consistent across all files."
|
||||
}
|
||||
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\GPOZaurrPermissionsInconsistentAfter.html -Verbose -Type GPOConsistency
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
$GPOZaurrDuplicates = [ordered] @{
|
||||
Name = 'Duplicate (CNF) Group Policies'
|
||||
Enabled = $true
|
||||
Action = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrDuplicateObject
|
||||
}
|
||||
Processing = {
|
||||
$Script:Reporting['GPODuplicates']['Variables']['RequireDeletion'] = $Script:Reporting['GPODuplicates']['Data'].Count
|
||||
if ($Script:Reporting['GPODuplicates']['Data'].Count -gt 0) {
|
||||
$Script:Reporting['GPODuplicates']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPODuplicates']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = @{
|
||||
RequireDeletion = 0
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Resources = @(
|
||||
'https://social.technet.microsoft.com/wiki/contents/articles/15435.active-directory-duplicate-object-name-resolution.aspx'
|
||||
'https://kickthatcomputer.wordpress.com/2014/11/22/seek-and-destroy-duplicate-ad-objects-with-cnf-in-the-name/'
|
||||
)
|
||||
Summary = {
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"CNF objects, Conflict objects or Duplicate Objects are created in Active Directory when there is simultaneous creation of an AD object under the same container "
|
||||
"on two separate Domain Controllers near about the same time or before the replication occurs. "
|
||||
"This results in a conflict and the same is exhibited by a CNF (Duplicate) object. "
|
||||
"While it doesn't nessecary has a huge impact on Active Directory it's important to keep Active Directory in proper, healthy state. "
|
||||
}
|
||||
New-HTMLText -Text 'As it stands currently there are ', $Script:Reporting['GPODuplicates']['Data'].Count, ' CNF (Duplicate) Group Policy objects to be deleted.' -FontSize 10pt -FontWeight normal, bold, normal
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
& $Script:GPOConfiguration['GPODuplicates']['Summary']
|
||||
}
|
||||
New-HTMLPanel {
|
||||
New-HTMLChart {
|
||||
New-ChartLegend -Names 'Bad' -Color PaleGreen, Salmon
|
||||
New-ChartBar -Name 'Duplicate (CNF) object' -Value $Script:Reporting['GPODuplicates']['Data'].Count
|
||||
} -Title 'Duplicate (CNF) Objects' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policy CNF (Duplicate) Objects' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPODuplicates']['Data'] -Filtering {
|
||||
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
if ($Script:Reporting['GPODuplicates']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPODuplicates']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Steps to fix - Remove duplicate (CNF) objects' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLText -Text 'Following steps will guide you how to remove duplicate objects'
|
||||
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 fixing duplicate GPO objects. To generate new report please use:"
|
||||
New-HTMLCodeBlock -Code {
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrDuplicateObjectsBefore.html -Verbose -Type GPODuplicates
|
||||
}
|
||||
New-HTMLText -Text {
|
||||
"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-GPOZaurrDuplicateObject
|
||||
$GPOOutput | Format-Table # do your actions as desired
|
||||
}
|
||||
New-HTMLText -Text "It provides same data as you see in table above just doesn't prettify it for you."
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Remove CNF objects' {
|
||||
New-HTMLText -Text "Following command when executed, runs internally command that lists all duplicate objects."
|
||||
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 {
|
||||
Remove-GPOZaurrDuplicateObject -WhatIf -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 changed matches expected data. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrDuplicateObject -Verbose -LimitProcessing 2
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed removes only first X duplicate objects. 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."
|
||||
}
|
||||
}
|
||||
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\GPOZaurrDuplicateObjectsAfter.html -Verbose -Type GPODuplicates
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
$GPOZaurrFiles = [ordered] @{
|
||||
Name = 'SYSVOL (NetLogon) Files List'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrFiles
|
||||
}
|
||||
Processing = {
|
||||
|
||||
}
|
||||
Variables = @{
|
||||
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOFiles']['Data'] -Filtering
|
||||
if ($Script:Reporting['GPOFiles']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOFiles']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
$GPOZaurrList = [ordered] @{
|
||||
Name = 'Group Policy Summary'
|
||||
Enabled = $true
|
||||
Action = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurr
|
||||
}
|
||||
Processing = {
|
||||
foreach ($GPO in $Script:Reporting['GPOList']['Data']) {
|
||||
if ($GPO.Linked -eq $false -and $GPO.Empty -eq $true) {
|
||||
# Not linked, Empty
|
||||
$Script:Reporting['GPOList']['Variables']['GPOEmptyAndUnlinked']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPOEmptyOrUnlinked']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPONotLinked']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPOEmpty']++
|
||||
} elseif ($GPO.Linked -eq $true -and $GPO.Empty -eq $true) {
|
||||
# Linked, But EMPTY
|
||||
$Script:Reporting['GPOList']['Variables']['GPOLinkedButEmpty']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPOEmptyOrUnlinked']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPOEmpty']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPOLinked']++
|
||||
} elseif ($GPO.Linked -eq $false) {
|
||||
# Not linked, but not EMPTY
|
||||
$Script:Reporting['GPOList']['Variables']['GPONotLinked']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPOEmptyOrUnlinked']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPONotEmpty']++
|
||||
} elseif ($GPO.Empty -eq $true) {
|
||||
# Linked, But EMPTY
|
||||
$Script:Reporting['GPOList']['Variables']['GPOEmpty']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPOEmptyOrUnlinked']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPOLinked']++
|
||||
} else {
|
||||
# Linked, not EMPTY
|
||||
$Script:Reporting['GPOList']['Variables']['GPOValid']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPOLinked']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPONotEmpty']++
|
||||
}
|
||||
if ($GPO.LinksDisabledCount -eq $GPO.LinksCount -and $GPO.LinksCount -gt 0) {
|
||||
$Script:Reporting['GPOList']['Variables']['GPOLinkedButLinkDisabled']++
|
||||
}
|
||||
|
||||
if ($GPO.ComputerOptimized -eq $true) {
|
||||
$Script:Reporting['GPOList']['Variables']['ComputerOptimizedYes']++
|
||||
} else {
|
||||
$Script:Reporting['GPOList']['Variables']['ComputerOptimizedNo']++
|
||||
}
|
||||
if ($GPO.ComputerProblem -eq $true) {
|
||||
$Script:Reporting['GPOList']['Variables']['ComputerProblemYes']++
|
||||
} else {
|
||||
$Script:Reporting['GPOList']['Variables']['ComputerProblemNo']++
|
||||
}
|
||||
if ($GPO.UserOptimized -eq $true) {
|
||||
$Script:Reporting['GPOList']['Variables']['UserOptimizedYes']++
|
||||
} else {
|
||||
$Script:Reporting['GPOList']['Variables']['UserOptimizedNo']++
|
||||
}
|
||||
if ($GPO.UserProblem -eq $true) {
|
||||
$Script:Reporting['GPOList']['Variables']['UserProblemYes']++
|
||||
} else {
|
||||
$Script:Reporting['GPOList']['Variables']['UserProblemNo']++
|
||||
}
|
||||
if ($GPO.UserProblem -or $GPO.ComputerProblem) {
|
||||
$Script:Reporting['GPOList']['Variables']['GPOWithProblems']++
|
||||
}
|
||||
}
|
||||
$Script:Reporting['GPOList']['Variables']['GPOTotal'] = $Script:Reporting['GPOList']['Data'].Count
|
||||
if ($Script:Reporting['GPOList']['Variables']['GPOEmptyOrUnlinked'].Count -gt 0) {
|
||||
$Script:Reporting['GPOList']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPOList']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = @{
|
||||
GPOWithProblems = 0
|
||||
ComputerOptimizedYes = 0
|
||||
ComputerOptimizedNo = 0
|
||||
ComputerProblemYes = 0
|
||||
ComputerProblemNo = 0
|
||||
UserOptimizedYes = 0
|
||||
UserOptimizedNo = 0
|
||||
UserProblemYes = 0
|
||||
UserProblemNo = 0
|
||||
GPONotLinked = 0
|
||||
GPOLinked = 0
|
||||
GPOEmpty = 0
|
||||
GPONotEmpty = 0
|
||||
GPOEmptyAndUnlinked = 0
|
||||
GPOEmptyOrUnlinked = 0
|
||||
GPOLinkedButEmpty = 0
|
||||
GPOValid = 0
|
||||
GPOLinkedButLinkDisabled = 0
|
||||
GPOTotal = 0
|
||||
}
|
||||
Overview = {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -Text 'Following chart presents ', 'Linked / Empty and Unlinked Group Policies' -FontSize 10pt -FontWeight normal, bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies total: ', $Script:Reporting['GPOList']['Variables']['GPOTotal'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies valid: ", $Script:Reporting['GPOList']['Variables']['GPOValid'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies to delete: ", $Script:Reporting['GPOList']['Variables']['GPOEmptyOrUnlinked'] -FontWeight normal, bold {
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies that are unlinked (are not doing anything currently): ', $Script:Reporting['GPOList']['Variables']['GPONotLinked'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are empty (have no settings): ", $Script:Reporting['GPOList']['Variables']['GPOEmpty'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are linked, but empty: ", $Script:Reporting['GPOList']['Variables']['GPOLinkedButEmpty'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are linked, but link disabled: ", $Script:Reporting['GPOList']['Variables']['GPOLinkedButLinkDisabled'] -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLText -FontSize 10pt -Text 'Usually empty or unlinked Group Policies are safe to delete.'
|
||||
New-HTMLChart -Title 'Group Policies Summary' {
|
||||
New-ChartBarOptions -Type barStacked
|
||||
#New-ChartLegend -Names 'Unlinked', 'Linked', 'Empty', 'Total' -Color Salmon, PaleGreen, PaleVioletRed, PaleTurquoise
|
||||
New-ChartLegend -Names 'Good', 'Bad' -Color PaleGreen, Salmon
|
||||
#New-ChartBar -Name 'Group Policies' -Value $Script:Reporting['GPOList']['Variables']['GPONotLinked'], $Script:Reporting['GPOList']['Variables']['GPOLinked'], $Script:Reporting['GPOList']['Variables']['GPOEmpty'], $Script:Reporting['GPOList']['Variables']['GPOTotal']
|
||||
New-ChartBar -Name 'Linked' -Value $Script:Reporting['GPOList']['Variables']['GPOLinked'], $Script:Reporting['GPOList']['Variables']['GPONotLinked']
|
||||
New-ChartBar -Name 'Empty' -Value $Script:Reporting['GPOList']['Variables']['GPONotEmpty'], $Script:Reporting['GPOList']['Variables']['GPOEmpty']
|
||||
New-ChartBar -Name 'Valid' -Value $Script:Reporting['GPOList']['Variables']['GPOValid'], $Script:Reporting['GPOList']['Variables']['GPOEmptyOrUnlinked']
|
||||
} -TitleAlignment center
|
||||
}
|
||||
}
|
||||
Summary = {
|
||||
New-HTMLText -TextBlock {
|
||||
"Over time Administrators add more and more group policies, as business requirements change. "
|
||||
"Due to neglection or thinking it may serve it's purpose later on a lot of Group Policies often have no value at all. "
|
||||
"Either the Group Policy is not linked to anything and just stays unlinked forever, or GPO is linked, but the link (links) are disabled. "
|
||||
"Additionally sometimes new GPO is created without any settings or the settings are removed over time, but GPO stays in place. "
|
||||
} -FontSize 10pt
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies total: ', $Script:Reporting['GPOList']['Variables']['GPOTotal'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies valid: ", $Script:Reporting['GPOList']['Variables']['GPOValid'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies to delete: ", $Script:Reporting['GPOList']['Variables']['GPOEmptyOrUnlinked'] -FontWeight normal, bold {
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies that are unlinked (are not doing anything currently): ', $Script:Reporting['GPOList']['Variables']['GPONotLinked'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are empty (have no settings): ", $Script:Reporting['GPOList']['Variables']['GPOEmpty'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are linked, but empty: ", $Script:Reporting['GPOList']['Variables']['GPOLinkedButEmpty'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are linked, but link disabled: ", $Script:Reporting['GPOList']['Variables']['GPOLinkedButLinkDisabled'] -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text "Additionally, we're reviewing Group Policies that have their section disabled, but contain data. Please review them and make sure this configuration is as expected!" -FontSize 10pt
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies with problems: ', $Script:Reporting['GPOList']['Variables']['GPOWithProblems'] -FontWeight normal, bold {
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies that have content (computer), but are disabled: ', $Script:Reporting['GPOList']['Variables']['ComputerProblemYes'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that have content (user), but are disabled: ", $Script:Reporting['GPOList']['Variables']['UserProblemYes'] -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text "For best performance it's recommended that if there are no settings of certain kind (Computer or User settings) it's best to disable them. " -FontSize 10pt
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies with optimization: ' -FontWeight normal, bold {
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies that are optimized (computer) ', $Script:Reporting['GPOList']['Variables']['ComputerOptimizedYes'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are optimized (user): ", $Script:Reporting['GPOList']['Variables']['UserOptimizedYes'] -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
New-HTMLListItem -Text 'Group Policies without optimization: ' -FontWeight normal, bold {
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies that are not optimized (computer): ', $Script:Reporting['GPOList']['Variables']['ComputerOptimizedNo'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are not optimized (user): ", $Script:Reporting['GPOList']['Variables']['UserOptimizedNo'] -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -TextBlock {
|
||||
'All empty or unlinked Group Policies can be automatically deleted. Please review output in the table and follow steps below table to cleanup Group Policies. '
|
||||
'GPOs that have content, but are disabled require manual intervention. '
|
||||
"If performance is an issue you should consider disabling user or computer sections of GPO when those are not used. "
|
||||
} -FontSize 10pt
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
& $Script:GPOConfiguration['GPOList']['Summary']
|
||||
}
|
||||
New-HTMLPanel {
|
||||
New-HTMLChart -Title 'Group Policies Empty & Unlinked' {
|
||||
New-ChartBarOptions -Type barStacked
|
||||
New-ChartLegend -Names 'Yes', 'No' -Color SpringGreen, Salmon
|
||||
New-ChartBar -Name 'Linked' -Value $Script:Reporting['GPOList']['Variables']['GPOLinked'], $Script:Reporting['GPOList']['Variables']['GPONotLinked']
|
||||
New-ChartBar -Name 'Empty' -Value $Script:Reporting['GPOList']['Variables']['GPONotEmpty'], $Script:Reporting['GPOList']['Variables']['GPOEmpty']
|
||||
New-ChartBar -Name 'Valid' -Value $Script:Reporting['GPOList']['Variables']['GPOValid'], $Script:Reporting['GPOList']['Variables']['GPOEmptyOrUnlinked']
|
||||
New-ChartBar -Name 'With problem (computers)' -Value $Script:Reporting['GPOList']['Variables']['ComputerProblemNo'], $Script:Reporting['GPOList']['Variables']['ComputerProblemYes']
|
||||
New-ChartBar -Name 'With problem (users)' -Value $Script:Reporting['GPOList']['Variables']['UserProblemNo'], $Script:Reporting['GPOList']['Variables']['UserProblemYes']
|
||||
New-ChartBar -Name 'Optimized Computers' -Value $Script:Reporting['GPOList']['Variables']['ComputerOptimizedYes'], $Script:Reporting['GPOList']['Variables']['ComputerOptimizedNo']
|
||||
New-ChartBar -Name 'Optimized Users' -Value $Script:Reporting['GPOList']['Variables']['UserOptimizedYes'], $Script:Reporting['GPOList']['Variables']['UserOptimizedNo']
|
||||
} -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policies List' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOList']['Data'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Empty' -Value $true -BackgroundColor Salmon -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'Linked' -Value $false -BackgroundColor Salmon -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ComputerProblem' -Value $true -BackgroundColor Salmon -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'UserProblem' -Value $true -BackgroundColor Salmon -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ComputerOptimized' -Value $false -BackgroundColor Salmon -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'UserOptimized' -Value $false -BackgroundColor Salmon -TextTransform capitalize -ComparisonType string
|
||||
# reverse
|
||||
New-HTMLTableCondition -Name 'Empty' -Value $false -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'Linked' -Value $true -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ComputerProblem' -Value $false -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'UserProblem' -Value $false -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ComputerOptimized' -Value $true -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'UserOptimized' -Value $true -BackgroundColor SpringGreen -TextTransform capitalize -ComparisonType string
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
if ($Script:Reporting['GPOList']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOList']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Steps to fix - Empty & Unlinked Group Policies' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLText -Text 'Following steps will guide you how to remove empty or unlinked group policies'
|
||||
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\GPOZaurrEmptyUnlinked.html -Verbose -Type GPOList
|
||||
}
|
||||
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-GPOZaurr
|
||||
$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 'Remove GPOs that are EMPTY or UNLINKED' {
|
||||
New-HTMLText -Text @(
|
||||
"Following command when executed removes every ",
|
||||
"EMPTY"
|
||||
" or "
|
||||
"NOT LINKED"
|
||||
" Group Policy. Make sure when running it for the first time to run it with ",
|
||||
"WhatIf",
|
||||
" parameter as shown below to prevent accidental removal.",
|
||||
"Make sure to use BackupPath which will make sure that for each GPO that is about to be deleted a backup is made to folder on a desktop."
|
||||
) -FontWeight normal, bold, normal, bold, normal, bold, normal, normal -Color Black, Red, Black, Red, Black
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Empty, Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf
|
||||
}
|
||||
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. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Empty, Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed deletes only first empty or unlinked 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."
|
||||
"Please make sure to check if backup is made as well before going all in."
|
||||
}
|
||||
New-HTMLText -Text "If there's nothing else to be deleted on SYSVOL side, 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\GPOZaurrEmptyUnlinkedAfter.html -Verbose -Type GPOList
|
||||
}
|
||||
New-HTMLText -Text "If there are no more empty or unlinked GPOs in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
$GPOZaurrNetLogonPermissions = [ordered] @{
|
||||
Name = 'NetLogon Permissions'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrNetLogon
|
||||
}
|
||||
Processing = {
|
||||
foreach ($File in $Script:Reporting['NetLogonPermissions']['Data']) {
|
||||
if ($File.FileSystemRights -eq 'Owner') {
|
||||
$Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwners']++
|
||||
if ($File.PrincipalType -eq 'WellKnownAdministrative') {
|
||||
$Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersAdministrative']++
|
||||
} elseif ($File.PrincipalType -eq 'Administrative') {
|
||||
$Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersAdministrative']++
|
||||
} else {
|
||||
$Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersNotAdministrative']++
|
||||
}
|
||||
if ($File.PrincipalSid -eq 'S-1-5-32-544') {
|
||||
$Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersAdministrators']++
|
||||
} elseif ($File.PrincipalType -in 'WellKnownAdministrative', 'Administrative') {
|
||||
$Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersAdministrativeNotAdministrators']++
|
||||
$Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersToFix']++
|
||||
} else {
|
||||
$Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersToFix']++
|
||||
}
|
||||
$Script:Reporting['NetLogonPermissions']['Variables']['Owner'].Add($File)
|
||||
} else {
|
||||
$Script:Reporting['NetLogonPermissions']['Variables']['NonOwner'].Add($File)
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersToFix'].Count -gt 0) {
|
||||
$Script:Reporting['NetLogonPermissions']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['NetLogonPermissions']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = @{
|
||||
NetLogonOwners = 0
|
||||
NetLogonOwnersAdministrators = 0
|
||||
NetLogonOwnersNotAdministrative = 0
|
||||
NetLogonOwnersAdministrative = 0
|
||||
NetLogonOwnersAdministrativeNotAdministrators = 0
|
||||
NetLogonOwnersToFix = 0
|
||||
Owner = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
NonOwner = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
}
|
||||
Overview = {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -Text 'Following chart presents ', 'NetLogon Summary' -FontSize 10pt -FontWeight normal, bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'NetLogon Files in Total: ', $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwners'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'NetLogon BUILTIN\Administrators as Owner: ', $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersAdministrators'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "NetLogon Owners requiring change: ", $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersToFix'] -FontWeight normal, bold {
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Not Administrative: ', $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersNotAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Administrative, but not BUILTIN\Administrators: ', $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersAdministrativeNotAdministrators'] -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
} -FontSize 10pt
|
||||
#New-HTMLText -FontSize 10pt -Text 'Those problems must be resolved before doing other clenaup activities.'
|
||||
New-HTMLChart {
|
||||
New-ChartPie -Name 'Correct Owners' -Value $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersAdministrators'] -Color LightGreen
|
||||
New-ChartPie -Name 'Incorrect Owners' -Value $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersToFix'] -Color Crimson
|
||||
} -Title 'NetLogon Owners' -TitleAlignment center
|
||||
}
|
||||
New-HTMLPanel {
|
||||
|
||||
}
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLTab -Name 'NetLogon Owners' {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -TextBlock {
|
||||
"Following table shows NetLogon file owners. It's important that NetLogon file owners are set to BUILTIN\Administrators (SID: S-1-5-32-544). "
|
||||
"Owners have full control over the file object. Current owner of the file may be an Administrator but it doesn't guarentee that he will be in the future. "
|
||||
"That's why as a best-practice it's recommended to change any non-administrative owners to BUILTIN\Administrators, and even Administrative accounts should be replaced with it. "
|
||||
} -FontSize 10pt
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'NetLogon Files in Total: ', $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwners'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'NetLogon BUILTIN\Administrators as Owner: ', $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersAdministrators'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "NetLogon Owners requiring change: ", $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersToFix'] -FontWeight normal, bold {
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Not Administrative: ', $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersNotAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Administrative, but not BUILTIN\Administrators: ', $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersAdministrativeNotAdministrators'] -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text "Follow the steps below table to get NetLogon Owners into compliant state." -FontSize 10pt
|
||||
}
|
||||
New-HTMLPanel {
|
||||
New-HTMLChart {
|
||||
New-ChartPie -Name 'Correct Owners' -Value $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersAdministrators'] -Color LightGreen
|
||||
New-ChartPie -Name 'Incorrect Owners' -Value $Script:Reporting['NetLogonPermissions']['Variables']['NetLogonOwnersToFix'] -Color Crimson
|
||||
} -Title 'NetLogon Owners' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'NetLogon Files List' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['NetLogonPermissions']['Variables']['Owner'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'PrincipalSid' -Value "S-1-5-32-544" -BackgroundColor LightGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'PrincipalSid' -Value "S-1-5-32-544" -BackgroundColor Salmon -ComparisonType string -Operator ne
|
||||
New-HTMLTableCondition -Name 'PrincipalType' -Value "WellKnownAdministrative" -BackgroundColor LightGreen -ComparisonType string -Operator eq
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['NetLogonPermissions']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['NetLogonPermissions']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Steps to fix NetLogon Owners ' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLText -Text 'Following steps will guide you how to fix NetLogon Owners and make them compliant.'
|
||||
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\GPOZaurrNetLogonBefore.html -Verbose -Type NetLogon
|
||||
}
|
||||
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 {
|
||||
$NetLogonOutput = Get-GPOZaurrNetLogon -Verbose
|
||||
$NetLogonOutput | 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 'Set non-compliant file owners to BUILTIN\Administrators' {
|
||||
New-HTMLText -Text "Following command when executed runs internally command that lists all file owners and if it doesn't match changes it BUILTIN\Administrators. It doesn't change compliant owners."
|
||||
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 {
|
||||
Repair-GPOZaurrNetLogonOwner -Verbose -WhatIf
|
||||
}
|
||||
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. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Repair-GPOZaurrNetLogonOwner -Verbose -LimitProcessing 2
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed sets new owner only on first X non-compliant NetLogon files. 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 '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\GPOZaurrNetLogonAfter.html -Verbose -Type NetLogon
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLTab -Name 'NetLogon Permissions' {
|
||||
New-HTMLSection -Name 'NetLogon Files List' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['NetLogonPermissions']['Variables']['NonOwner'] -Filtering
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
$GPOZaurrOrphans = [ordered] @{
|
||||
Name = 'Orphaned Group Policies'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrBroken
|
||||
}
|
||||
Processing = {
|
||||
foreach ($GPO in $Script:Reporting['GPOOrphans']['Data']) {
|
||||
if ($GPO.Status -eq 'Not available in AD') {
|
||||
$Script:Reporting['GPOOrphans']['Variables']['NotAvailableInAD']++
|
||||
$Script:Reporting['GPOOrphans']['Variables']['ToBeDeleted']++
|
||||
} elseif ($GPO.Status -eq 'Not available on SYSVOL') {
|
||||
$Script:Reporting['GPOOrphans']['Variables']['NotAvailableOnSysvol']++
|
||||
$Script:Reporting['GPOOrphans']['Variables']['ToBeDeleted']++
|
||||
} elseif ($GPO.Status -eq 'Permissions issue') {
|
||||
$Script:Reporting['GPOOrphans']['Variables']['NotAvailablePermissionIssue']++
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOOrphans']['Variables']['ToBeDeleted'].Count -gt 0) {
|
||||
$Script:Reporting['GPOOrphans']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPOOrphans']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = @{
|
||||
NotAvailableInAD = 0
|
||||
NotAvailableOnSysvol = 0
|
||||
NotAvailablePermissionIssue = 0
|
||||
ToBeDeleted = 0
|
||||
}
|
||||
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."
|
||||
}
|
||||
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['GPOOrphans']['Variables']['NotAvailableInAD'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Group Policies in AD, but no content on SYSVOL: ', $Script:Reporting['GPOOrphans']['Variables']['NotAvailableOnSysvol'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which couldn't be assed due to permissions issue: ", $Script:Reporting['GPOOrphans']['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['GPOOrphans']['Variables']['NotAvailableInAD'], $Script:Reporting['GPOOrphans']['Variables']['NotAvailableOnSysvol'], $Script:Reporting['GPOOrphans']['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
|
||||
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['GPOOrphans']['Variables']['NotAvailableInAD'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Group Policies in AD, but no content on SYSVOL: ', $Script:Reporting['GPOOrphans']['Variables']['NotAvailableOnSysvol'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which couldn't be assed due to permissions issue: ", $Script:Reporting['GPOOrphans']['Variables']['NotAvailablePermissionIssue'] -FontWeight normal, bold
|
||||
} -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['GPOOrphans']['Summary']
|
||||
}
|
||||
New-HTMLPanel {
|
||||
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['GPOOrphans']['Variables']['NotAvailableInAD'], $Script:Reporting['GPOOrphans']['Variables']['NotAvailableOnSysvol'], $Script:Reporting['GPOOrphans']['Variables']['NotAvailablePermissionIssue']
|
||||
} -Title 'Broken / Orphaned Group Policies' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Health State of Group Policies' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOOrphans']['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 "Permissions issue" -BackgroundColor MediumVioletRed -ComparisonType string -Color White
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
if ($Script:Reporting['GPOOrphans']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOOrphans']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Steps to fix - Not available on SYSVOL / Active Directory' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLText -Text 'Following steps will guide you how to fix GPOs which are not available on SYSVOL or AD.'
|
||||
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 GPOOrphans
|
||||
}
|
||||
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
|
||||
$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 'Fix GPOs not available on SYSVOL' {
|
||||
New-HTMLText -Text "Following command when executed runs cleanup procedure that removes all broken GPOs on SYSVOL side."
|
||||
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 {
|
||||
Remove-GPOZaurrBroken -Type SYSVOL -WhatIf
|
||||
}
|
||||
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. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrBroken -Type SYSVOL -LimitProcessing 2 -BackupPath $Env:UserProfile\Desktop\GPOSYSVOLBackup
|
||||
}
|
||||
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."
|
||||
}
|
||||
New-HTMLText -Text "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 AD' {
|
||||
New-HTMLText -Text "Following command when executed runs cleanup procedure that removes all broken GPOs on Active Directory side."
|
||||
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 {
|
||||
Remove-GPOZaurrBroken -Type AD -WhatIf
|
||||
}
|
||||
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. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrBroken -Type AD -LimitProcessing 2 -BackupPath $Env:UserProfile\Desktop\GPOSYSVOLBackup
|
||||
}
|
||||
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."
|
||||
}
|
||||
New-HTMLText -Text "If there's nothing else to be deleted on AD side, 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 GPOOrphans
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,36 @@
|
||||
$Script:GpoZaurrOwners = @{
|
||||
Data = $null
|
||||
Execute = { Get-GPOZaurrOwner -IncludeSysvol }
|
||||
Processing = {
|
||||
foreach ($GPO in $Script:GpoZaurrOwners['Data']) {
|
||||
$GPOZaurrOwners = [ordered] @{
|
||||
Name = 'Group Policy Owners'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = { Get-GPOZaurrOwner -IncludeSysvol }
|
||||
Processing = {
|
||||
foreach ($GPO in $Script:Reporting['GPOOwners']['Data']) {
|
||||
if ($GPO.IsOwnerConsistent) {
|
||||
$Script:GpoZaurrOwners['Variables']['IsConsistent']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['IsConsistent']++
|
||||
} else {
|
||||
$Script:GpoZaurrOwners['Variables']['IsNotConsistent']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['IsNotConsistent']++
|
||||
}
|
||||
if ($GPO.IsOwnerAdministrative) {
|
||||
$Script:GpoZaurrOwners['Variables']['IsAdministrative']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['IsAdministrative']++
|
||||
} else {
|
||||
$Script:GpoZaurrOwners['Variables']['IsNotAdministrative']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['IsNotAdministrative']++
|
||||
}
|
||||
if (($GPO.IsOwnerAdministrative -eq $false -or $GPO.IsOwnerConsistent -eq $false) -and $GPO.SysvolExists -eq $true) {
|
||||
$Script:GpoZaurrOwners['Variables']['WillFix']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillFix']++
|
||||
} elseif ($GPO.SysvolExists -eq $false) {
|
||||
$Script:GpoZaurrOwners['Variables']['RequiresDiffFix']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['RequiresDiffFix']++
|
||||
} else {
|
||||
$Script:GpoZaurrOwners['Variables']['WillNotTouch']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillNotTouch']++
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOOwners']['Variables']['WillFix'].Count -gt 0) {
|
||||
$Script:Reporting['GPOOwners']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPOOwners']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = [ordered] @{
|
||||
Variables = @{
|
||||
IsAdministrative = 0
|
||||
IsNotAdministrative = 0
|
||||
IsConsistent = 0
|
||||
@@ -31,68 +39,79 @@
|
||||
RequiresDiffFix = 0
|
||||
WillNotTouch = 0
|
||||
}
|
||||
Overview = {
|
||||
Overview = {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -Text 'Following chart presents Group Policy owners and whether they are administrative and consistent. By design an owner of Group Policy should be Domain Admins or Enterprise Admins group only to prevent malicious takeover. ', `
|
||||
"It's also important that owner in Active Directory matches owner on SYSVOL (file system)." -FontSize 10pt
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Administrative Owners: ', $Script:GpoZaurrOwners['Variables']['IsAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Non-Administrative Owners: ', $Script:GpoZaurrOwners['Variables']['IsNotAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Owners consistent in AD and SYSVOL: ", $Script:GpoZaurrOwners['Variables']['IsConsistent'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Owners not-consistent in AD and SYSVOL: ", $Script:GpoZaurrOwners['Variables']['IsNotConsistent'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Administrative Owners: ', $Script:Reporting['GPOOwners']['Variables']['IsAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Non-Administrative Owners: ', $Script:Reporting['GPOOwners']['Variables']['IsNotAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Owners consistent in AD and SYSVOL: ", $Script:Reporting['GPOOwners']['Variables']['IsConsistent'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Owners not-consistent in AD and SYSVOL: ", $Script:Reporting['GPOOwners']['Variables']['IsNotConsistent'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLChart {
|
||||
New-ChartBarOptions -Type barStacked
|
||||
New-ChartLegend -Name 'Yes', 'No' -Color PaleGreen, Orchid
|
||||
New-ChartBar -Name 'Is administrative' -Value $Script:GpoZaurrOwners['Variables']['IsAdministrative'], $Script:GpoZaurrOwners['Variables']['IsNotAdministrative']
|
||||
New-ChartBar -Name 'Is consistent' -Value $Script:GpoZaurrOwners['Variables']['IsConsistent'], $Script:GpoZaurrOwners['Variables']['IsNotConsistent']
|
||||
New-ChartBar -Name 'Is administrative' -Value $Script:Reporting['GPOOwners']['Variables']['IsAdministrative'], $Script:Reporting['GPOOwners']['Variables']['IsNotAdministrative']
|
||||
New-ChartBar -Name 'Is consistent' -Value $Script:Reporting['GPOOwners']['Variables']['IsConsistent'], $Script:Reporting['GPOOwners']['Variables']['IsNotConsistent']
|
||||
} -Title 'Group Policy Owners' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
Solution = {
|
||||
Summary = {
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"By default GPO creation is usually maintained by Domain Admins or Enterprise Admins. "
|
||||
"When GPO is created by member of Domain Admins or Enterprise Admins group the GPO Owner is set to Domain Admins. "
|
||||
"When GPO is created by member of Group Policy Creator Owners or other group has delegated rights to create a GPO the owner of said GPO is not Domain Admins group but is assigned to relevant user. "
|
||||
"GPO Owners should be Domain Admins or Enterprise Admins to prevent abuse. If that isn't so it means owner is able to fully control GPO and potentially change it's settings in uncontrolled way. "
|
||||
"While at the moment of creation of new GPO it's not a problem, in long term it's possible such person may no longer be admin, yet keep their rights over GPO. "
|
||||
}
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"As you're aware Group Policies are stored in 2 places. In Active Directory (metadata) and SYSVOL (settings). This means that there are 2 places where GPO Owners exists. "
|
||||
"This also means that for multiple reasons AD and SYSVOL can be out of sync when it comes to their permissions which can lead to uncontrolled ability to modify them. "
|
||||
"Ownership in Active Directory and Ownership of SYSVOL for said GPO are required to be the same. "
|
||||
}
|
||||
New-HTMLText -Text "Here's a short summary of ", "Group Policy Owners", ": " -FontSize 10pt -FontWeight normal, bold, normal
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Administrative Owners: ', $Script:Reporting['GPOOwners']['Variables']['IsAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Non-Administrative Owners: ', $Script:Reporting['GPOOwners']['Variables']['IsNotAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Owners consistent in AD and SYSVOL: ", $Script:Reporting['GPOOwners']['Variables']['IsConsistent'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Owners not-consistent in AD and SYSVOL: ", $Script:Reporting['GPOOwners']['Variables']['IsNotConsistent'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text "This gives us: "
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies requiring owner change: ', $Script:Reporting['GPOOwners']['Variables']['WillFix'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which can't be fixed (no SYSVOL?): ", $Script:Reporting['GPOOwners']['Variables']['RequiresDiffFix'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies unaffected: ", $Script:Reporting['GPOOwners']['Variables']['WillNotTouch'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"By default GPO creation is usually maintained by Domain Admins or Enterprise Admins. "
|
||||
"When GPO is created by member of Domain Admins or Enterprise Admins group the GPO Owner is set to Domain Admins. "
|
||||
"When GPO is created by member of Group Policy Creator Owners or other group has delegated rights to create a GPO the owner of said GPO is not Domain Admins group but is assigned to relevant user. "
|
||||
"GPO Owners should be Domain Admins or Enterprise Admins to prevent abuse. If that isn't so it means owner is able to fully control GPO and potentially change it's settings in uncontrolled way. "
|
||||
"While at the moment of creation of new GPO it's not a problem, in long term it's possible such person may no longer be admin, yet keep their rights over GPO. "
|
||||
}
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"As you're aware Group Policies are stored in 2 places. In Active Directory (metadata) and SYSVOL (settings). This means that there are 2 places where GPO Owners exists. "
|
||||
"This also means that for multiple reasons AD and SYSVOL can be out of sync when it comes to their permissions which can lead to uncontrolled ability to modify them. "
|
||||
"Ownership in Active Directory and Ownership of SYSVOL for said GPO are required to be the same. "
|
||||
}
|
||||
New-HTMLText -Text "Here's a short summary of ", "Group Policy Owners", ": " -FontSize 10pt -FontWeight normal, bold, normal
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Administrative Owners: ', $Script:GpoZaurrOwners['Variables']['IsAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Non-Administrative Owners: ', $Script:GpoZaurrOwners['Variables']['IsNotAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Owners consistent in AD and SYSVOL: ", $Script:GpoZaurrOwners['Variables']['IsConsistent'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Owners not-consistent in AD and SYSVOL: ", $Script:GpoZaurrOwners['Variables']['IsNotConsistent'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text "This gives us: "
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies requiring owner change: ', $Script:GpoZaurrOwners['Variables']['WillFix'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which can't be fixed (no SYSVOL?): ", $Script:GpoZaurrOwners['Variables']['RequiresDiffFix'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies unaffected: ", $Script:GpoZaurrOwners['Variables']['WillNotTouch'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
& $Script:GPOConfiguration['GPOOwners']['Summary']
|
||||
}
|
||||
New-HTMLPanel {
|
||||
New-HTMLChart {
|
||||
New-ChartBarOptions -Type barStacked
|
||||
New-ChartLegend -Name 'Yes', 'No' -Color LightGreen, Salmon
|
||||
New-ChartBar -Name 'Is administrative' -Value $Script:GpoZaurrOwners['Variables']['IsAdministrative'], $Script:GpoZaurrOwners['Variables']['IsNotAdministrative']
|
||||
New-ChartBar -Name 'Is consistent' -Value $Script:GpoZaurrOwners['Variables']['IsConsistent'], $Script:GpoZaurrOwners['Variables']['IsNotConsistent']
|
||||
New-ChartBar -Name 'Is administrative' -Value $Script:Reporting['GPOOwners']['Variables']['IsAdministrative'], $Script:Reporting['GPOOwners']['Variables']['IsNotAdministrative']
|
||||
New-ChartBar -Name 'Is consistent' -Value $Script:Reporting['GPOOwners']['Variables']['IsConsistent'], $Script:Reporting['GPOOwners']['Variables']['IsNotConsistent']
|
||||
} -Title 'Group Policy Owners' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policy Owners' {
|
||||
New-HTMLTable -DataTable $Script:GpoZaurrOwners['Data'] -Filtering {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOOwners']['Data'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'IsOwnerConsistent' -Value $false -BackgroundColor Salmon -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'IsOwnerAdministrative' -Value $false -BackgroundColor Salmon -ComparisonType string -Row
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
if ($Script:Reporting['GPOOwners']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOOwners']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Steps to fix Group Policy Owners' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
@@ -0,0 +1,30 @@
|
||||
$GPOZaurrPassword = [ordered] @{
|
||||
Name = 'Group Policy Passwords'
|
||||
Enabled = $true
|
||||
Action = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrPassword
|
||||
}
|
||||
Processing = {
|
||||
|
||||
}
|
||||
Variables = @{
|
||||
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPassword']['Data'] -Filtering
|
||||
|
||||
if ($Script:Reporting['GPOPassword']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPassword']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
$GPOZaurrPermissions = [ordered] @{
|
||||
Name = 'Group Policy Permissions'
|
||||
Enabled = $true
|
||||
Action = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrPermission -Type All -IncludePermissionType GpoEditDeleteModifySecurity, GpoEdit, GpoCustom #-IncludeOwner
|
||||
}
|
||||
Processing = {
|
||||
|
||||
}
|
||||
Variables = @{
|
||||
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPermissions']['Data'] -Filtering
|
||||
if ($Script:Reporting['GPOPermissions']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPermissions']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
$GPOZaurrPermissionsRoot = [ordered] @{
|
||||
Name = 'Group Policies Root Permissions'
|
||||
Enabled = $true
|
||||
Action = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrPermissionRoot -SkipNames
|
||||
}
|
||||
Processing = {
|
||||
|
||||
}
|
||||
Variables = @{
|
||||
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPermissionsRoot']['Data'] -Filtering
|
||||
if ($Script:Reporting['GPOPermissionsRoot']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPermissionsRoot']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
$GPOZaurrSysVolLegacyFiles = [ordered] @{
|
||||
Name = 'SYSVOL Legacy ADM Files'
|
||||
Enabled = $false
|
||||
Action = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrLegacyFiles
|
||||
}
|
||||
Processing = {
|
||||
|
||||
}
|
||||
Variables = @{
|
||||
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLTable -DataTable $Script:Reporting['SysVolLegacyFiles']['Data'] -Filtering
|
||||
if ($Script:Reporting['SysVolLegacyFiles']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['SysVolLegacyFiles']['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,4 +1,5 @@
|
||||
function New-GPOZaurrReportConsole {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[System.Collections.IDictionary] $Results
|
||||
)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
function Reset-GPOZaurrStatus {
|
||||
param(
|
||||
|
||||
)
|
||||
#if (-not $Script:GPOConfigurationClean) {
|
||||
# $Script:GPOConfigurationClean = Copy-Dictionary -Dictionary $Script:GPOConfiguration
|
||||
#} else {
|
||||
# $Script:GPOConfiguration = Copy-Dictionary -Dictionary $Script:GPOConfigurationClean
|
||||
#}
|
||||
if (-not $Script:DefaultTypes) {
|
||||
$Script:DefaultTypes = foreach ($T in $Script:GPOConfiguration.Keys) {
|
||||
if ($Script:GPOConfiguration[$T].Enabled) {
|
||||
$T
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($T in $Script:GPOConfiguration.Keys) {
|
||||
$Script:GPOConfiguration[$T]['Enabled'] = $false
|
||||
}
|
||||
foreach ($T in $Script:DefaultTypes) {
|
||||
$Script:GPOConfiguration[$T]['Enabled'] = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
$ScriptGPOConfigurationGPOConsistency = [ordered] @{
|
||||
Chart = {
|
||||
New-ChartLegend -Names 'Bad', 'Good' -Color PaleGreen, Salmon
|
||||
New-ChartBarOptions -Type barStacked
|
||||
New-ChartLegend -Name 'Consistent', 'Inconsistent'
|
||||
New-ChartBar -Name 'TopLevel' -Value $Inconsistent[0].Count, $Inconsistent[1].Count
|
||||
New-ChartBar -Name 'Inherited' -Value $InconsistentInside[0].Count, $InconsistentInside[1].Count
|
||||
}
|
||||
List = {
|
||||
New-HTMLListItem -Text 'Top level permissions consistency: ', $Inconsistent[0].Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Inherited permissions consistency: ', $InconsistentInside[0].Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Inconsistent top level permissions: ', $Inconsistent[1].Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Inconsistent inherited permissions: ", $InconsistentInside[1].Count -FontWeight normal, bold
|
||||
}
|
||||
Wizard = {
|
||||
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 fixing permissions inconsistencies. To generate new report please use:"
|
||||
New-HTMLCodeBlock -Code {
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrPermissionsInconsistentBefore.html -Verbose -Type GPOConsistency
|
||||
}
|
||||
New-HTMLText -Text {
|
||||
"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-GPOZaurrPermissionConsistency
|
||||
$GPOOutput | Format-Table # do your actions as desired
|
||||
}
|
||||
New-HTMLText -Text "It provides same data as you see in table above just doesn't prettify it for you."
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Fix inconsistent permissions' {
|
||||
New-HTMLText -Text "Following command when executed fixes inconsistent permissions."
|
||||
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-HTMLText -Text "Make sure to fill in TargetDomain to match your Domain Admin permission account"
|
||||
|
||||
New-HTMLCodeBlock -Code {
|
||||
Repair-GPOZaurrPermissionConsistency -IncludeDomains "TargetDomain" -Verbose -WhatIf
|
||||
}
|
||||
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. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Repair-GPOZaurrPermissionConsistency -LimitProcessing 2 -IncludeDomains "TargetDomain"
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed repairs only first X inconsistent permissions. Use LimitProcessing parameter to prevent mass fixing 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-HTMLText -Text "If there's nothing else to be fixed, we can skip to next step step"
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Fix inconsistent downlevel permissions' {
|
||||
New-HTMLText -Text "Unfortunetly this step is manual until automation is developed. "
|
||||
New-HTMLText -Text "If there are inconsistent permissions found inside GPO one has to fix them manually by going into SYSVOL and making sure inheritance is enabled, and that permissions are consistent across all files."
|
||||
}
|
||||
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\GPOZaurrPermissionsInconsistentAfter.html -Verbose -Type GPOConsistency
|
||||
}
|
||||
New-HTMLText -Text "If everything is health in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
$ScriptGPOConfigurationNetLogon = [ordered] @{
|
||||
List = {
|
||||
New-HTMLListItem -Text 'NetLogon Files in Total: ', $NetLogonOwners.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'NetLogon BUILTIN\Administrators as Owner: ', $NetLogonOwnersAdministrators.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "NetLogon Owners requiring change: ", $NetLogonOwnersToFix.Count -FontWeight normal, bold {
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Not Administrative: ', $NetLogonOwnersNotAdministrative.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Administrative, but not BUILTIN\Administrators: ', $NetLogonOwnersAdministrativeNotAdministrators.Count -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
}
|
||||
Wizard = {
|
||||
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\GPOZaurrNetLogonBefore.html -Verbose -Type NetLogon
|
||||
}
|
||||
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 {
|
||||
$NetLogonOutput = Get-GPOZaurrNetLogon -Verbose
|
||||
$NetLogonOutput | 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 'Set non-compliant file owners to BUILTIN\Administrators' {
|
||||
New-HTMLText -Text "Following command when executed runs internally command that lists all file owners and if it doesn't match changes it BUILTIN\Administrators. It doesn't change compliant owners."
|
||||
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 {
|
||||
Repair-GPOZaurrNetLogonOwner -Verbose -WhatIf
|
||||
}
|
||||
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. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Repair-GPOZaurrNetLogonOwner -Verbose -LimitProcessing 2
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed sets new owner only on first X non-compliant NetLogon files. 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 '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\GPOZaurrNetLogonAfter.html -Verbose -Type NetLogon
|
||||
}
|
||||
New-HTMLText -Text "If everything is healthy in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,147 +1,15 @@
|
||||
$Script:GPOConfiguration = [ordered] @{
|
||||
GPOOrphans = [ordered] @{
|
||||
Wizard = {
|
||||
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 GPOOrphans
|
||||
}
|
||||
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
|
||||
$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 'Fix GPOs not available on SYSVOL' {
|
||||
New-HTMLText -Text "Following command when executed runs cleanup procedure that removes all broken GPOs on SYSVOL side."
|
||||
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 {
|
||||
Remove-GPOZaurrBroken -Type SYSVOL -WhatIf
|
||||
}
|
||||
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. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrBroken -Type SYSVOL -LimitProcessing 2 -BackupPath $Env:UserProfile\Desktop\GPOSYSVOLBackup
|
||||
}
|
||||
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."
|
||||
}
|
||||
New-HTMLText -Text "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 AD' {
|
||||
New-HTMLText -Text "Following command when executed runs cleanup procedure that removes all broken GPOs on Active Directory side."
|
||||
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 {
|
||||
Remove-GPOZaurrBroken -Type AD -WhatIf
|
||||
}
|
||||
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. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrBroken -Type AD -LimitProcessing 2 -BackupPath $Env:UserProfile\Desktop\GPOSYSVOLBackup
|
||||
}
|
||||
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."
|
||||
}
|
||||
New-HTMLText -Text "If there's nothing else to be deleted on AD side, 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 GPOOrphans
|
||||
}
|
||||
New-HTMLText -Text "If everything is healthy in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
}
|
||||
}
|
||||
GPOList = [ordered] @{
|
||||
List = {
|
||||
|
||||
}
|
||||
Wizard = {
|
||||
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\GPOZaurrEmptyUnlinked.html -Verbose -Type GPOList
|
||||
}
|
||||
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-GPOZaurr
|
||||
$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 'Remove GPOs that are EMPTY or UNLINKED' {
|
||||
New-HTMLText -Text @(
|
||||
"Following command when executed removes every ",
|
||||
"EMPTY"
|
||||
" or "
|
||||
"NOT LINKED"
|
||||
" Group Policy. Make sure when running it for the first time to run it with ",
|
||||
"WhatIf",
|
||||
" parameter as shown below to prevent accidental removal.",
|
||||
"Make sure to use BackupPath which will make sure that for each GPO that is about to be deleted a backup is made to folder on a desktop."
|
||||
) -FontWeight normal, bold, normal, bold, normal, bold, normal, normal -Color Black, Red, Black, Red, Black
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Empty, Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf
|
||||
}
|
||||
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. Once happy with results please follow with command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Empty, Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed deletes only first empty or unlinked 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."
|
||||
"Please make sure to check if backup is made as well before going all in."
|
||||
}
|
||||
New-HTMLText -Text "If there's nothing else to be deleted on SYSVOL side, 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\GPOZaurrEmptyUnlinkedAfter.html -Verbose -Type GPOList
|
||||
}
|
||||
New-HTMLText -Text "If there are no more empty or unlinked GPOs in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
}
|
||||
}
|
||||
GPOConsistency = $ScriptGPOConfigurationGPOConsistency
|
||||
NetLogon = $ScriptGPOConfigurationNetLogon
|
||||
GPOOwners = $ScriptGPOConfigurationGPOOwners
|
||||
GPOOrphans = $GPOZaurrOrphans
|
||||
GPOOwners = $GPOZaurrOwners
|
||||
GPOConsistency = $GPOZaurrConsistency
|
||||
GPODuplicates = $GPOZaurrDuplicates
|
||||
GPOList = $GPOZaurrList
|
||||
GPOPassword = $GPOZaurrPassword
|
||||
GPOPermissions = $GPOZaurrPermissions
|
||||
GPOPermissionsRoot = $GPOZaurrPermissionsRoot
|
||||
GPOFiles = $GPOZaurrFiles
|
||||
GPOBlockedInheritance = $GPOZaurrBlockedInheritance
|
||||
GPOAnalysis = $GPOZaurrAnalysis
|
||||
NetLogonPermissions = $GPOZaurrNetLogonPermissions
|
||||
SysVolLegacyFiles = $GPOZaurrSysVolLegacyFiles
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
[switch] $PermissionsOnly,
|
||||
[switch] $OwnerOnly,
|
||||
[switch] $Limited,
|
||||
|
||||
[switch] $ReturnObject,
|
||||
[System.Collections.IDictionary] $ADAdministrativeGroups
|
||||
)
|
||||
Begin {
|
||||
@@ -43,7 +43,7 @@
|
||||
Write-Warning "Get-GPOZaurr - Failed to get GPOReport: $($_.Exception.Message). Skipping."
|
||||
continue
|
||||
}
|
||||
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $_ -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups
|
||||
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $_ -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups -ReturnObject:$ReturnObject.IsPresent
|
||||
} else {
|
||||
$_
|
||||
}
|
||||
@@ -61,7 +61,7 @@
|
||||
Write-Warning "Get-GPOZaurr - Failed to get GPOReport: $($_.Exception.Message). Skipping."
|
||||
continue
|
||||
}
|
||||
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $_ -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups
|
||||
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $_ -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups -ReturnObject:$ReturnObject.IsPresent
|
||||
} else {
|
||||
$_
|
||||
}
|
||||
@@ -79,7 +79,7 @@
|
||||
Write-Warning "Get-GPOZaurr - Failed to get GPOReport: $($_.Exception.Message). Skipping."
|
||||
continue
|
||||
}
|
||||
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $_ -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups
|
||||
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $_ -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups -ReturnObject:$ReturnObject.IsPresent
|
||||
} else {
|
||||
$_
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
function Get-GPOZaurrDuplicateObject {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[alias('ForestName')][string] $Forest,
|
||||
[string[]] $ExcludeDomains,
|
||||
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation
|
||||
)
|
||||
|
||||
$getWinADDuplicateObjectSplat = @{
|
||||
Forest = $Forest
|
||||
IncludeDomains = $IncludeDomains
|
||||
ExcludeDomains = $ExcludeDomains
|
||||
ExtendedForestInformation = $ExtendedForestInformation
|
||||
PartialMatchDistinguishedName = "*,CN=Policies,CN=System,DC=*"
|
||||
Extended = $true
|
||||
}
|
||||
|
||||
$DuplicateObjects = Get-WinADDuplicateObject @getWinADDuplicateObjectSplat
|
||||
$DuplicateObjects
|
||||
}
|
||||
@@ -13,9 +13,16 @@
|
||||
$FilesAll = foreach ($Domain in $ForestInformation.Domains) {
|
||||
$Path = -join ("\\", $Domain, '\Netlogon')
|
||||
$PathOnSysvol = -join ("\\", $Domain, "\SYSVOL\", $Domain, "\Scripts")
|
||||
$Files = Get-ChildItem -LiteralPath $Path -Recurse -Force
|
||||
foreach ($_ in $Files) {
|
||||
$ACL = Get-Acl -Path $_.FullName
|
||||
$Files = Get-ChildItem -LiteralPath $Path -Recurse -Force -ErrorVariable Err -ErrorAction SilentlyContinue
|
||||
foreach ($e in $err) {
|
||||
Write-Warning "Get-GPOZaurrNetLogon - Listing file failed with error $($e.Exception.Message) ($($e.CategoryInfo.Reason))"
|
||||
}
|
||||
foreach ($File in $Files) {
|
||||
try {
|
||||
$ACL = Get-Acl -Path $File.FullName -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrNetLogon - ACL reading failed for $($File.FullName) with error $($_.Exception.Message) ($($_.CategoryInfo.Reason))"
|
||||
}
|
||||
if ($ACL.Owner) {
|
||||
$IdentityOwner = Convert-Identity -Identity $ACL.Owner -Verbose:$false
|
||||
} else {
|
||||
@@ -24,19 +31,19 @@
|
||||
if (-not $OwnerOnly) {
|
||||
if (-not $SkipOwner) {
|
||||
[PSCustomObject] @{
|
||||
FullName = $_.FullName
|
||||
Extension = $_.Extension
|
||||
CreationTime = $_.CreationTime
|
||||
LastAccessTime = $_.LastAccessTime
|
||||
LastWriteTime = $_.LastWriteTime
|
||||
Attributes = $_.Attributes
|
||||
FullName = $File.FullName
|
||||
Extension = $File.Extension
|
||||
CreationTime = $File.CreationTime
|
||||
LastAccessTime = $File.LastAccessTime
|
||||
LastWriteTime = $File.LastWriteTime
|
||||
Attributes = $File.Attributes
|
||||
AccessControlType = 'Allow' # : Allow
|
||||
Principal = $IdentityOwner.Name # : BUILTIN\Administrators
|
||||
PrincipalSid = $IdentityOwner.SID
|
||||
PrincipalType = $IdentityOwner.Type
|
||||
FileSystemRights = 'Owner' # : FullControl
|
||||
IsInherited = $false
|
||||
FullNameOnSysVol = $_.FullName.Replace($Path, $PathOnSysvol)
|
||||
FullNameOnSysVol = $File.FullName.Replace($Path, $PathOnSysvol)
|
||||
#Owner = $ACL.Owner
|
||||
}
|
||||
}
|
||||
@@ -44,33 +51,33 @@
|
||||
foreach ($Perm in $FilePermission) {
|
||||
$Identity = Convert-Identity -Identity $Perm.Principal -Verbose:$false
|
||||
[PSCustomObject] @{
|
||||
FullName = $_.FullName
|
||||
Extension = $_.Extension
|
||||
CreationTime = $_.CreationTime
|
||||
LastAccessTime = $_.LastAccessTime
|
||||
LastWriteTime = $_.LastWriteTime
|
||||
Attributes = $_.Attributes
|
||||
FullName = $File.FullName
|
||||
Extension = $File.Extension
|
||||
CreationTime = $File.CreationTime
|
||||
LastAccessTime = $File.LastAccessTime
|
||||
LastWriteTime = $File.LastWriteTime
|
||||
Attributes = $File.Attributes
|
||||
AccessControlType = $Perm.AccessControlType # : Allow
|
||||
Principal = $Identity.Name # : BUILTIN\Administrators
|
||||
PrincipalSid = $Identity.SID
|
||||
PrincipalType = $Identity.Type
|
||||
FileSystemRights = $Perm.FileSystemRights # : FullControl
|
||||
IsInherited = $Perm.IsInherited # : True
|
||||
FullNameOnSysVol = $_.FullName.Replace($Path, $PathOnSysvol)
|
||||
FullNameOnSysVol = $File.FullName.Replace($Path, $PathOnSysvol)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
[PSCustomObject] @{
|
||||
FullName = $_.FullName
|
||||
Extension = $_.Extension
|
||||
CreationTime = $_.CreationTime
|
||||
LastAccessTime = $_.LastAccessTime
|
||||
LastWriteTime = $_.LastWriteTime
|
||||
Attributes = $_.Attributes
|
||||
FullName = $File.FullName
|
||||
Extension = $File.Extension
|
||||
CreationTime = $File.CreationTime
|
||||
LastAccessTime = $File.LastAccessTime
|
||||
LastWriteTime = $File.LastWriteTime
|
||||
Attributes = $File.Attributes
|
||||
Owner = $IdentityOwner.Name
|
||||
OwnerSid = $IdentityOwner.SID
|
||||
OwnerType = $IdentityOwner.Type
|
||||
FullNameOnSysVol = $_.FullName.Replace($Path, $PathOnSysvol)
|
||||
FullNameOnSysVol = $File.FullName.Replace($Path, $PathOnSysvol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+84
-103
@@ -1,4 +1,35 @@
|
||||
function Get-GPOZaurrPassword {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Tries to find CPassword in Group Policies or given path and translate it to readable value
|
||||
|
||||
.DESCRIPTION
|
||||
Tries to find CPassword in Group Policies or given path and translate it to readable value
|
||||
|
||||
.PARAMETER Forest
|
||||
Specify forest name. By default current forest is used
|
||||
|
||||
.PARAMETER ExcludeDomains
|
||||
Exclude Domain or Domains
|
||||
|
||||
.PARAMETER IncludeDomains
|
||||
Include only certain Domain or Domains
|
||||
|
||||
.PARAMETER ExtendedForestInformation
|
||||
Ability to provide extended forest information in advanced scenarios
|
||||
|
||||
.PARAMETER GPOPath
|
||||
Path where Group Policy content is located or where backup is located
|
||||
|
||||
.EXAMPLE
|
||||
Get-GPOZaurrPassword -GPOPath 'C:\Users\przemyslaw.klys\Desktop\GPOExport_2020.10.12'
|
||||
|
||||
.EXAMPLE
|
||||
Get-GPOZaurrPassword
|
||||
|
||||
.NOTES
|
||||
General notes
|
||||
#>
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[alias('ForestName')][string] $Forest,
|
||||
@@ -7,115 +38,65 @@
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation,
|
||||
[string[]] $GPOPath
|
||||
)
|
||||
if (-not $GPOPath) {
|
||||
if (-not $ExtendedForestInformation) {
|
||||
$ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
} else {
|
||||
$ForestInformation = $ExtendedForestInformation
|
||||
}
|
||||
|
||||
[Array] $GPOPath = foreach ($Domain in $ForestInformation.Domains) {
|
||||
-join ('\\', $Domain, '\SYSVOL\', $Domain, '\Policies')
|
||||
}
|
||||
}
|
||||
if (-not $GPOPath) {
|
||||
return
|
||||
}
|
||||
foreach ($Path in $GPOPath) {
|
||||
#Extract the all XML files in the Folders
|
||||
$Items = Get-ChildItem -LiteralPath $Path -Recurse -Filter *.xml
|
||||
$Output = foreach ($XMLFileName in $Items) {
|
||||
#Convert XML in a String file
|
||||
[string]$XMLString = Get-Content ($XMLFileName.FullName)
|
||||
#Check if Cpassword Exist in the file
|
||||
if ($XMLString.Contains("cpassword")) {
|
||||
#Take the Cpassword Value from XML String file
|
||||
[string]$Cpassword = [regex]::matches($XMLString, '(cpassword=).+?(?=\")')
|
||||
$Cpassword = $Cpassword.split('(\")')[1]
|
||||
#Check if Cpassword has a value
|
||||
if ($Cpassword.Length -gt 20 -and $Cpassword -notlike '*cpassword*') {
|
||||
$Mod = ($Cpassword.length % 4)
|
||||
switch ($Mod) {
|
||||
'1' { $Cpassword = $Cpassword.Substring(0, $Cpassword.Length - 1) }
|
||||
'2' { $Cpassword += ('=' * (4 - $Mod)) }
|
||||
'3' { $Cpassword += ('=' * (4 - $Mod)) }
|
||||
}
|
||||
$Base64Decoded = [Convert]::FromBase64String($Cpassword)
|
||||
$AesObject = [System.Security.Cryptography.AesCryptoServiceProvider]::new()
|
||||
#Use th AES Key
|
||||
[Byte[]] $AesKey = @(0x4e, 0x99, 0x06, 0xe8, 0xfc, 0xb6, 0x6c, 0xc9, 0xfa, 0xf4, 0x93, 0x10, 0x62, 0x0f, 0xfe, 0xe8, 0xf4, 0x96, 0xe8, 0x06, 0xcc, 0x05, 0x79, 0x90, 0x20, 0x9b, 0x09, 0xa4, 0x33, 0xb6, 0x6c, 0x1b)
|
||||
$AesIV = New-Object Byte[]($AesObject.IV.Length)
|
||||
$AesObject.IV = $AesIV
|
||||
$AesObject.Key = $AesKey
|
||||
$DecryptorObject = $AesObject.CreateDecryptor()
|
||||
[Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)
|
||||
#Convert Hash variable in a String valute
|
||||
$Password = [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
|
||||
} else {
|
||||
$Password = ''
|
||||
}
|
||||
#[string]$GPOguid = [regex]::matches($XMLFileName.DirectoryName, '(?<=\{).+?(?=\})')
|
||||
#$GPODetail = Get-GPO -guid $GPOguid
|
||||
[xml] $XMLContent = $XMLString
|
||||
|
||||
#if (-not $XMLContent.gpo.Computer.ExtensionData.Extension.LocalUsersAndGroups.User.Properties.cpassword -and -not $XMLContent.gpo.User.ExtensionData.Extension.DriveMapSettings.Drive.Properties.cpassword) {
|
||||
#Write-Host ''
|
||||
#}
|
||||
if ($GPOPath) {
|
||||
foreach ($Path in $GPOPath) {
|
||||
$Items = Get-ChildItem -LiteralPath $Path -Recurse -Filter *.xml -ErrorAction SilentlyContinue -ErrorVariable err
|
||||
$Output = foreach ($XMLFileName in $Items) {
|
||||
$Password = Find-GPOPassword -Path $XMLFileName.FullName
|
||||
if ($Password) {
|
||||
$PasswordStatus = $true
|
||||
} else {
|
||||
$PasswordStatus = $false
|
||||
if ($XMLFileName.FullName -match '{\w{8}-\w{4}-\w{4}-\w{4}-\w{12}}') {
|
||||
$GPOGUID = $matches[0]
|
||||
}
|
||||
[PSCustomObject] @{
|
||||
RootPath = $Path
|
||||
PasswordFile = $XMLFileName.FullName
|
||||
GUID = $GPOGUID
|
||||
Password = $Password
|
||||
}
|
||||
}
|
||||
|
||||
[PsCustomObject] @{
|
||||
'Name' = $XMLContent.GPO.Name
|
||||
'Links' = $XMLContent.GPO.LinksTo #| Select-Object -ExpandProperty SOMPath
|
||||
'Enabled' = $XMLContent.GPO.GpoStatus
|
||||
'PasswordStatus' = $PasswordStatus
|
||||
#'GPO' = $XMLContent.gpo.Computer.ExtensionData.Extension.LocalUsersAndGroups
|
||||
'User' = $XMLContent.gpo.Computer.ExtensionData.Extension.LocalUsersAndGroups.User.name
|
||||
'Cpassword' = $XMLContent.gpo.Computer.ExtensionData.Extension.LocalUsersAndGroups.User.Properties.cpassword
|
||||
'CpasswordMap' = $XMLContent.gpo.User.ExtensionData.Extension.DriveMapSettings.Drive.Properties.cpassword
|
||||
'Password' = $Password
|
||||
'GUID' = $XMLContent.GPO.Identifier.Identifier.InnerText
|
||||
|
||||
'Domain' = $XMLContent.GPO.Identifier.Domain
|
||||
|
||||
'ComputerSettingsAvailable' = if ($null -eq $XMLContent.GPO.Computer.ExtensionData) { $false } else { $true }
|
||||
'ComputerSettingsStatus' = if ($XMLContent.GPO.Computer.VersionDirectory -eq 0 -and $XMLContent.GPO.Computer.VersionSysvol -eq 0) { "NeverModified" } else { "Modified" }
|
||||
'ComputerEnabled' = [bool] $XMLContent.GPO.Computer.Enabled
|
||||
'ComputerSetttingsVersionIdentical' = if ($XMLContent.GPO.Computer.VersionDirectory -eq $XMLContent.GPO.Computer.VersionSysvol) { $true } else { $false }
|
||||
'ComputerSettings' = $XMLContent.GPO.Computer.ExtensionData.Extension
|
||||
|
||||
'UserSettingsAvailable' = if ($null -eq $XMLContent.GPO.User.ExtensionData) { $false } else { $true }
|
||||
'UserEnabled' = [bool] $XMLContent.GPO.User.Enabled
|
||||
'UserSettingsStatus' = if ($XMLContent.GPO.User.VersionDirectory -eq 0 -and $XMLContent.GPO.User.VersionSysvol -eq 0) { "NeverModified" } else { "Modified" }
|
||||
'UserSettingsVersionIdentical' = if ($XMLContent.GPO.User.VersionDirectory -eq $XMLContent.GPO.User.VersionSysvol) { $true } else { $false }
|
||||
'UserSettings' = $XMLContent.GPO.User.ExtensionData.Extension
|
||||
|
||||
|
||||
'CreationTime' = [DateTime] $XMLContent.GPO.CreatedTime
|
||||
'ModificationTime' = [DateTime] $XMLContent.GPO.ModifiedTime
|
||||
'ReadTime' = [DateTime] $XMLContent.GPO.ReadTime
|
||||
|
||||
'WMIFilter' = $GPO.WmiFilter.name
|
||||
'WMIFilterDescription' = $GPO.WmiFilter.Description
|
||||
'Path' = $GPO.Path
|
||||
#'SDDL' = if ($Splitter -ne '') { $XMLContent.GPO.SecurityDescriptor.SDDL.'#text' -join $Splitter } else { $XMLContent.GPO.SecurityDescriptor.SDDL.'#text' }
|
||||
'ACL' = $XMLContent.GPO.SecurityDescriptor.Permissions.TrusteePermissions | ForEach-Object -Process {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
$Path = -join ('\\', $Domain, '\SYSVOL\', $Domain, '\Policies')
|
||||
#Extract the all XML files in the Folder
|
||||
$Items = Get-ChildItem -LiteralPath $Path -Recurse -Filter *.xml -ErrorAction SilentlyContinue -ErrorVariable err
|
||||
$Output = foreach ($XMLFileName in $Items) {
|
||||
$Password = Find-GPOPassword -Path $XMLFileName.FullName
|
||||
if ($Password) {
|
||||
# match regex
|
||||
if ($XMLFileName.FullName -match '{\w{8}-\w{4}-\w{4}-\w{4}-\w{12}}') {
|
||||
$GPOGUID = $matches[0]
|
||||
$GPO = Get-GPOZaurrAD -GPOGuid $GPOGUID -IncludeDomains $Domain
|
||||
[PSCustomObject] @{
|
||||
'User' = $_.trustee.name.'#Text'
|
||||
'Permission Type' = $_.type.PermissionType
|
||||
'Inherited' = $_.Inherited
|
||||
'Permissions' = $_.Standard.GPOGroupedAccessEnum
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
PasswordFile = $XMLFileName.FullName
|
||||
Password = $Password
|
||||
Created = $GPO.Created
|
||||
Modified = $GPO.Modified
|
||||
Description = $GPO.Description
|
||||
}
|
||||
} else {
|
||||
[PSCustomObject] @{
|
||||
DisplayName = ''
|
||||
DomainName = ''
|
||||
GUID = ''
|
||||
PasswordFile = $XMLFileName.FullName
|
||||
Password = $Password
|
||||
Created = ''
|
||||
Modified = ''
|
||||
Description = ''
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#Write-Host "I find a Password [ " $Password " ] The GPO named:" $GPODetail" and th file is:" $XMLFileName
|
||||
|
||||
} #if($XMLContent.Contains("cpassword")
|
||||
}
|
||||
foreach ($e in $err) {
|
||||
Write-Warning "Get-GPOZaurrPassword - $($e.Exception.Message) ($($e.CategoryInfo.Reason))"
|
||||
}
|
||||
$Output
|
||||
}
|
||||
$Output
|
||||
}
|
||||
}
|
||||
@@ -44,17 +44,23 @@
|
||||
$GroupPolicies = Get-GPO @getGPOSplat
|
||||
$Count = 0
|
||||
$GroupPolicies | ForEach-Object -Process {
|
||||
$GPO = $_
|
||||
$Count++
|
||||
Write-Verbose "Get-GPOZaurrPermissionConsistency - Processing [$($_.DomainName)]($Count/$($GroupPolicies.Count)) $($_.DisplayName)"
|
||||
try {
|
||||
$IsConsistent = $_.IsAclConsistent()
|
||||
$ErrorMessage = ''
|
||||
} catch {
|
||||
$ErrorMessage = $_.Exception.Message
|
||||
Write-Warning "Get-GPOZaurrPermissionConsistency - Failed to get consistency: $($_.Exception.Message)."
|
||||
$IsConsistent = 'Not available'
|
||||
$SysVolpath = -join ('\\', $Domain, '\sysvol\', $Domain, '\Policies\{', $GPO.ID.GUID, '}')
|
||||
if (Test-Path -LiteralPath $SysVolpath) {
|
||||
try {
|
||||
$IsConsistent = $GPO.IsAclConsistent()
|
||||
$ErrorMessage = ''
|
||||
} catch {
|
||||
$ErrorMessage = $_.Exception.Message
|
||||
Write-Warning "Get-GPOZaurrPermissionConsistency - Processing $($GPO.DisplayName) / $($GPO.DomainName) failed to get consistency with error: $($_.Exception.Message)."
|
||||
$IsConsistent = 'Not available'
|
||||
}
|
||||
} else {
|
||||
Write-Warning "Get-GPOZaurrPermissionConsistency - Processing $($GPO.DisplayName) / $($GPO.DomainName) failed as path $SysvolPath doesn't exists!"
|
||||
$IsConsistent = $false
|
||||
}
|
||||
$SysVolpath = -join ('\\', $Domain, '\sysvol\', $Domain, '\Policies\{', $_.ID.GUID, '}')
|
||||
if ($VerifyInheritance) {
|
||||
if ($IsConsistent -eq $true) {
|
||||
$FolderPermissions = Get-WinADSharePermission -Path $SysVolpath -Verbose:$false
|
||||
|
||||
+97
-436
@@ -3,177 +3,88 @@
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[string] $FilePath,
|
||||
[ValidateSet(
|
||||
'GPOList', 'GPOOrphans', 'GPOPermissions', 'GPOPermissionsRoot', 'GPOFiles',
|
||||
'GPOConsistency', 'GPOOwners', 'GPOAnalysis',
|
||||
'NetLogon',
|
||||
'LegacyAdm'
|
||||
)][string[]] $Type
|
||||
[string[]] $Type,
|
||||
[switch] $PassThru,
|
||||
[switch] $HideHTML
|
||||
)
|
||||
Reset-GPOZaurrStatus # This makes sure types are at it's proper status
|
||||
|
||||
$Script:Reporting = [ordered] @{}
|
||||
# Provide version check for easy use
|
||||
$GPOZaurrVersion = Get-Command -Name 'Invoke-GPOZaurr' -ErrorAction SilentlyContinue
|
||||
$Script:Reporting['Version'] = Get-GitHubVersion -Cmdlet 'Invoke-GPOZaurr' -RepositoryOwner 'evotecit' -RepositoryName 'GPOZaurr'
|
||||
Write-Color '[i]', "[GPOZaurr] ", 'Version', ' [Informative] ', $Script:Reporting['Version'] -Color Yellow, DarkGray, Yellow, DarkGray, Magenta
|
||||
|
||||
[Array] $GitHubReleases = (Get-GitHubLatestRelease -Url "https://api.github.com/repos/evotecit/GpoZaurr/releases" -Verbose:$false)
|
||||
|
||||
$LatestVersion = $GitHubReleases[0]
|
||||
if (-not $LatestVersion.Errors) {
|
||||
if ($GPOZaurrVersion.Version -eq $LatestVersion.Version) {
|
||||
$Script:Reporting['Version'] = "GPOZaurr Current/Latest: $($LatestVersion.Version) at $($LatestVersion.PublishDate)"
|
||||
} elseif ($GPOZaurrVersion.Version -lt $LatestVersion.Version) {
|
||||
$Script:Reporting['Version'] = "GPOZaurr Current: $($GPOZaurrVersion.Version), Published: $($LatestVersion.Version) at $($LatestVersion.PublishDate). Update?"
|
||||
} elseif ($GPOZaurrVersion.Version -gt $LatestVersion.Version) {
|
||||
$Script:Reporting['Version'] = "GPOZaurr Current: $($GPOZaurrVersion.Version), Published: $($LatestVersion.Version) at $($LatestVersion.PublishDate). Lucky you!"
|
||||
}
|
||||
} else {
|
||||
$Script:Reporting['Version'] = "GPOZaurr Current: $($GPOZaurrVersion.Version)"
|
||||
}
|
||||
|
||||
# Gather data
|
||||
$TimeLog = Start-TimeLog
|
||||
if ($Type -contains 'GPOList' -or $null -eq $Type) {
|
||||
$TimeLogGPOList = Start-TimeLog
|
||||
Write-Verbose -Message "Invoke-GPOZaurr - Processing GPO List"
|
||||
$GPOSummary = Get-GPOZaurr
|
||||
$GPONotLinked = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$GPOLinked = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$GPOEmpty = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$GPONotEmpty = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$GPOEmptyAndUnlinked = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$GPOEmptyOrUnlinked = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$GPOLinkedButEmpty = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$GPOValid = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$GPOLinkedButLinkDisabled = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
foreach ($GPO in $GPOSummary) {
|
||||
if ($GPO.Linked -eq $false -and $GPO.Empty -eq $true) {
|
||||
# Not linked, Empty
|
||||
$GPOEmptyAndUnlinked.Add($GPO)
|
||||
$GPOEmptyOrUnlinked.Add($GPO)
|
||||
$GPONotLinked.Add($GPO)
|
||||
$GPOEmpty.Add($GPO)
|
||||
} elseif ($GPO.Linked -eq $true -and $GPO.Empty -eq $true) {
|
||||
# Linked, But EMPTY
|
||||
$GPOLinkedButEmpty.Add($GPO)
|
||||
$GPOEmptyOrUnlinked.Add($GPO)
|
||||
$GPOEmpty.Add($GPO)
|
||||
$GPOLinked.Add($GPO)
|
||||
} elseif ($GPO.Linked -eq $false) {
|
||||
# Not linked, but not EMPTY
|
||||
$GPONotLinked.Add($GPO)
|
||||
$GPOEmptyOrUnlinked.Add($GPO)
|
||||
$GPONotEmpty.Add($GPO)
|
||||
} elseif ($GPO.Empty -eq $true) {
|
||||
# Linked, But EMPTY
|
||||
$GPOEmpty.Add($GPO)
|
||||
$GPOEmptyOrUnlinked.Add($GPO)
|
||||
$GPOLinked.Add($GPO)
|
||||
} else {
|
||||
# Linked, not EMPTY
|
||||
$GPOValid.Add($GPO)
|
||||
$GPOLinked.Add($GPO)
|
||||
$GPONotEmpty.Add($GPO)
|
||||
}
|
||||
if ($GPO.LinksDisabledCount -eq $GPO.LinksCount -and $GPO.LinksCount -gt 0) {
|
||||
$GPOLinkedButLinkDisabled.Add($GPO)
|
||||
}
|
||||
}
|
||||
$GPOTotal = $GPOSummary.Count
|
||||
$TimeEndGPOList = Stop-TimeLog -Time $TimeLogGPOList -Option OneLiner
|
||||
Write-Verbose -Message "Invoke-GPOZaurr - Processing GPO List $TimeEndGPOList"
|
||||
}
|
||||
if ($Type -contains 'GPOOrphans' -or $null -eq $Type) {
|
||||
#Write-Color -Text "[Info] ", "Processing GPOOrphans" -Color Yellow, White
|
||||
Write-Verbose -Message "Invoke-GPOZaurr - Processing GPO Sysvol"
|
||||
$GPOOrphans = Get-GPOZaurrBroken
|
||||
|
||||
$NotAvailableInAD = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$NotAvailableOnSysvol = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$NotAvailablePermissionIssue = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
foreach ($_ in $GPOOrphans) {
|
||||
if ($_.Status -eq 'Not available in AD') {
|
||||
$NotAvailableInAD.Add($NotAvailableInAD)
|
||||
} elseif ($_.Status -eq 'Not available on SYSVOL') {
|
||||
$NotAvailableOnSysvol.Add($NotAvailableInAD)
|
||||
} elseif ( $_.Status -eq 'Permissions issue') {
|
||||
$NotAvailablePermissionIssue.Add($NotAvailableInAD)
|
||||
}
|
||||
# Verify requested types are supported
|
||||
$Supported = [System.Collections.Generic.List[string]]::new()
|
||||
[Array] $NotSupported = foreach ($T in $Type) {
|
||||
if ($T -notin $Script:GPOConfiguration.Keys ) {
|
||||
$T
|
||||
} else {
|
||||
$Supported.Add($T)
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOPermissions' -or $null -eq $Type) {
|
||||
#Write-Color -Text "[Info] ", "Processing GPOPermissions" -Color Yellow, White
|
||||
Write-Verbose -Message "Invoke-GPOZaurr - Processing GPO Permissions"
|
||||
$GPOPermissions = Get-GPOZaurrPermission -Type All -IncludePermissionType GpoEditDeleteModifySecurity, GpoEdit, GpoCustom -IncludeOwner
|
||||
if ($Supported) {
|
||||
Write-Color '[i]', "[GPOZaurr] ", 'Supported types', ' [Informative] ', "Chosen by user: ", ($Supported -join ', ') -Color Yellow, DarkGray, Yellow, DarkGray, Yellow, Magenta
|
||||
}
|
||||
if ($Type -contains 'GPOConsistency' -or $null -eq $Type) {
|
||||
Write-Verbose -Message "Invoke-GPOZaurr - Processing GPO Permissions Consistency"
|
||||
$GPOPermissionsConsistency = Get-GPOZaurrPermissionConsistency -Type All -VerifyInheritance
|
||||
[Array] $Inconsistent = $GPOPermissionsConsistency.Where( { $_.ACLConsistent -eq $true } , 'split' )
|
||||
[Array] $InconsistentInside = $GPOPermissionsConsistency.Where( { $_.ACLConsistentInside -eq $true }, 'split' )
|
||||
if ($NotSupported) {
|
||||
Write-Color '[i]', "[GPOZaurr] ", 'Not supported types', ' [Informative] ', "Following types are not supported: ", ($NotSupported -join ', ') -Color Yellow, DarkGray, Yellow, DarkGray, Yellow, Magenta
|
||||
Write-Color '[i]', "[GPOZaurr] ", 'Not supported types', ' [Informative] ', "Please use one/multiple from the list: ", ($Script:GPOConfiguration.Keys -join ', ') -Color Yellow, DarkGray, Yellow, DarkGray, Yellow, Magenta
|
||||
return
|
||||
}
|
||||
if ($Type -contains 'GPOPermissionsRoot' -or $null -eq $Type) {
|
||||
Write-Verbose -Message "Invoke-GPOZaurr - Processing GPO Permissions Root"
|
||||
$GPOPermissionsRoot = Get-GPOZaurrPermissionRoot -SkipNames
|
||||
}
|
||||
if ($Type -contains 'GPOOwners' -or $null -eq $Type) {
|
||||
$TimeLogGPOList = Start-TimeLog
|
||||
Write-Verbose "Invoke-GPOZaurr - Processing GPO Owners"
|
||||
$Script:GpoZaurrOwners['Data'] = & $Script:GpoZaurrOwners['Execute']
|
||||
& $Script:GpoZaurrOwners['Processing']
|
||||
$TimeEndGPOList = Stop-TimeLog -Time $TimeLogGPOList -Option OneLiner
|
||||
Write-Verbose -Message "Invoke-GPOZaurr - Processing GPO Owners $TimeEndGPOList"
|
||||
}
|
||||
if ($Type -contains 'NetLogon' -or $null -eq $Type) {
|
||||
$TimeLogSection = Start-TimeLog
|
||||
Write-Verbose "Get-GPOZaurrNetLogon - Processing NETLOGON Share"
|
||||
$NetLogon = Get-GPOZaurrNetLogon
|
||||
$NetLogonOwners = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$NetLogonOwnersAdministrators = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$NetLogonOwnersNotAdministrative = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$NetLogonOwnersAdministrative = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$NetLogonOwnersAdministrativeNotAdministrators = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$NetLogonOwnersToFix = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
foreach ($File in $Netlogon) {
|
||||
if ($File.FileSystemRights -eq 'Owner') {
|
||||
$NetLogonOwners.Add($File)
|
||||
|
||||
if ($File.PrincipalType -eq 'WellKnownAdministrative') {
|
||||
$NetLogonOwnersAdministrative.Add($File)
|
||||
} elseif ($File.PrincipalType -eq 'Administrative') {
|
||||
$NetLogonOwnersAdministrative.Add($File)
|
||||
} else {
|
||||
$NetLogonOwnersNotAdministrative.Add($File)
|
||||
# Lets make sure we only enable those types which are requestd by user
|
||||
if ($Type) {
|
||||
foreach ($T in $Script:GPOConfiguration.Keys) {
|
||||
$Script:GPOConfiguration[$T].Enabled = $false
|
||||
}
|
||||
# Lets enable all requested ones
|
||||
foreach ($T in $Type) {
|
||||
$Script:GPOConfiguration[$T].Enabled = $true
|
||||
}
|
||||
}
|
||||
|
||||
# Build data
|
||||
foreach ($T in $Script:GPOConfiguration.Keys) {
|
||||
if ($Script:GPOConfiguration[$T].Enabled -eq $true) {
|
||||
$Script:Reporting[$T] = [ordered] @{
|
||||
Name = $Script:GPOConfiguration[$T].Name
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
WarningsAndErrors = $null
|
||||
Time = $null
|
||||
Variables = Copy-Dictionary -Dictionary $Script:GPOConfiguration[$T]['Variables']
|
||||
}
|
||||
$TimeLogGPOList = Start-TimeLog
|
||||
Write-Color -Text '[i]', '[Start] ', $($Script:GPOConfiguration[$T]['Name']) -Color Yellow, DarkGray, Yellow
|
||||
$Script:Reporting[$T]['Data'] = Invoke-Command -ScriptBlock $Script:GPOConfiguration[$T]['Execute'] -WarningVariable CommandWarnings -ErrorVariable CommandErrors
|
||||
Invoke-Command -ScriptBlock $Script:GPOConfiguration[$T]['Processing']
|
||||
$Script:Reporting[$T]['WarningsAndErrors'] = @(
|
||||
foreach ($War in $CommandWarnings) {
|
||||
[PSCustomObject] @{
|
||||
Type = 'Warning'
|
||||
Comment = $War
|
||||
Reason = ''
|
||||
TargetName = ''
|
||||
}
|
||||
}
|
||||
|
||||
if ($File.PrincipalSid -eq 'S-1-5-32-544') {
|
||||
$NetLogonOwnersAdministrators.Add($File)
|
||||
} elseif ($File.PrincipalType -in 'WellKnownAdministrative', 'Administrative') {
|
||||
$NetLogonOwnersAdministrativeNotAdministrators.Add($File)
|
||||
$NetLogonOwnersToFix.Add($File)
|
||||
} else {
|
||||
$NetLogonOwnersToFix.Add($File)
|
||||
foreach ($Err in $CommandErrors) {
|
||||
[PSCustomObject] @{
|
||||
Type = 'Error'
|
||||
Comment = $Err
|
||||
Reason = $Err.CategoryInfo.Reason
|
||||
TargetName = $Err.CategoryInfo.TargetName
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
$TimeEndGPOList = Stop-TimeLog -Time $TimeLogGPOList -Option OneLiner
|
||||
$Script:Reporting[$T]['Time'] = $TimeEndGPOList
|
||||
Write-Color -Text '[i]', '[End ] ', $($Script:GPOConfiguration[$T]['Name']), " [Time to execute: $TimeEndGPOList]" -Color Yellow, DarkGray, Yellow, DarkGray
|
||||
}
|
||||
$TimeLogSectionEnd = Stop-TimeLog -Time $TimeLogSection -Option OneLiner
|
||||
Write-Verbose "Get-GPOZaurrNetLogon - Processing NETLOGON Share $TimeLogSectionEnd"
|
||||
}
|
||||
if ($Type -contains 'GPOAnalysis' -or $null -eq $Type) {
|
||||
Write-Verbose "Invoke-GPOZaurr - Processing GPO Analysis"
|
||||
$GPOContent = Invoke-GPOZaurrContent
|
||||
}
|
||||
if ($Type -contains 'GPOFiles') {
|
||||
Write-Verbose "Invoke-GPOZaurr - Processing GPOFiles"
|
||||
$GPOFiles = Get-GPOZaurrFiles
|
||||
}
|
||||
if ($Type -contains 'LegacyADM') {
|
||||
Write-Verbose "Invoke-GPOZaurr - Processing GPOFiles"
|
||||
$ADMLegacyFiles = Get-GPOZaurrLegacyFiles
|
||||
}
|
||||
$TimeEnd = Stop-TimeLog -Time $TimeLog -Option OneLiner
|
||||
Write-Verbose "Invoke-GPOZaurr - Data gathering time $TimeEnd"
|
||||
|
||||
# Generate pretty HTML
|
||||
Write-Verbose "Invoke-GPOZaurr - Generating HTML"
|
||||
New-HTML {
|
||||
$TimeLogHTML = Start-TimeLog
|
||||
Write-Color -Text '[i]', '[HTML ] ', 'Generating HTML report' -Color Yellow, DarkGray, Yellow
|
||||
New-HTML -Author 'Przemysław Kłys' -TitleText 'GPOZaurr Report' {
|
||||
New-HTMLTabStyle -BorderRadius 0px -TextTransform capitalize -BackgroundColorActive SlateGrey
|
||||
New-HTMLSectionStyle -BorderRadius 0px -HeaderBackGroundColor Grey -RemoveShadow
|
||||
New-HTMLPanelStyle -BorderRadius 0px
|
||||
@@ -185,290 +96,40 @@
|
||||
New-HTMLText -Text "Report generated on $(Get-Date)" -Color Blue
|
||||
} -JustifyContent flex-start -Invisible
|
||||
New-HTMLSection {
|
||||
New-HTMLText -Text $Script:Reporting['Version'] -Color Blue
|
||||
New-HTMLText -Text "GPOZaurr - $($Script:Reporting['Version'])" -Color Blue
|
||||
} -JustifyContent flex-end -Invisible
|
||||
}
|
||||
}
|
||||
|
||||
New-HTMLTab -Name 'Overview' {
|
||||
if ($Type -contains 'GPOConsistency' -or $Type -contains 'GPOList' -or $null -eq $Type) {
|
||||
New-HTMLSection -Invisible {
|
||||
if ($Type -contains 'GPOList' -or $null -eq $Type) {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -Text 'Following chart presents ', 'Linked / Empty and Unlinked Group Policies' -FontSize 10pt -FontWeight normal, bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies total: ', $GPOTotal -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies valid: ", $GPOValid.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies to delete: ", $GPOEmptyOrUnlinked.Count -FontWeight normal, bold {
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies that are unlinked (are not doing anything currently): ', $GPONotLinked.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are empty (have no settings): ", $GPOEmpty.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are linked, but empty: ", $GPOLinkedButEmpty.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are linked, but link disabled: ", $GPOLinkedButLinkDisabled.Count -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text 'Usually empty or unlinked Group Policies are safe to delete.'
|
||||
New-HTMLChart -Title 'Group Policies Summary' {
|
||||
New-ChartBarOptions -Type barStacked
|
||||
#New-ChartLegend -Names 'Unlinked', 'Linked', 'Empty', 'Total' -Color Salmon, PaleGreen, PaleVioletRed, PaleTurquoise
|
||||
New-ChartLegend -Names 'Good', 'Bad' -Color PaleGreen, Salmon
|
||||
#New-ChartBar -Name 'Group Policies' -Value $GPONotLinked.Count, $GPOLinked.Count, $GPOEmpty.Count, $GPOTotal
|
||||
New-ChartBar -Name 'Linked' -Value $GPOLinked.Count, $GPONotLinked.Count
|
||||
New-ChartBar -Name 'Empty' -Value $GPONotEmpty.Count, $GPOEmpty.Count
|
||||
New-ChartBar -Name 'Valid' -Value $GPOValid.Count, $GPOEmptyOrUnlinked.Count
|
||||
} -TitleAlignment center
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOConsistency' -or $null -eq $Type) {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -Text 'Following chart presents ', 'permissions consistency between Active Directory and SYSVOL for Group Policies' -FontSize 10pt -FontWeight normal, bold
|
||||
New-HTMLList -Type Unordered {
|
||||
& $Script:GPOConfiguration['GPOConsistency']['List']
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text 'Having incosistent permissions on AD in comparison to those on SYSVOL can lead to uncontrolled ability to modify them.'
|
||||
New-HTMLChart {
|
||||
& $Script:GPOConfiguration['GPOConsistency']['Chart']
|
||||
} -Title 'Permissions Consistency' -TitleAlignment center
|
||||
}
|
||||
if ($Type.Count -eq 1) {
|
||||
foreach ($T in $Script:GPOConfiguration.Keys) {
|
||||
if ($Script:GPOConfiguration[$T].Enabled -eq $true) {
|
||||
& $Script:GPOConfiguration[$T]['Solution']
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($T in $Script:GPOConfiguration.Keys) {
|
||||
if ($Script:GPOConfiguration[$T].Enabled -eq $true) {
|
||||
New-HTMLTab -Name $Script:GPOConfiguration[$T]['Name'] {
|
||||
& $Script:GPOConfiguration[$T]['Solution']
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOOwners' -or $Type -contains 'GPOOrphans' -or $null -eq $Type) {
|
||||
New-HTMLSection -Invisible {
|
||||
if ($Type -contains 'GPOOwners' -or $null -eq $Type) {
|
||||
if ($Script:GpoZaurrOwners['Overview']) {
|
||||
& $Script:GpoZaurrOwners['Overview']
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOOrphans' -or $null -eq $Type) {
|
||||
New-HTMLPanel {
|
||||
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: ', $NotAvailableInAD.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Group Policies in AD, but no content on SYSVOL: ', $NotAvailableOnSysvol.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which couldn't be assed due to permissions issue: ", $NotAvailablePermissionIssue.Count -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 $NotAvailableInAD.Count, $NotAvailableOnSysvol.Count, $NotAvailablePermissionIssue.Count
|
||||
} -Title 'Broken / Orphaned Group Policies' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'NetLogon' -or $null -eq $Type) {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -Text 'Following chart presents ', 'NetLogon Summary' -FontSize 10pt -FontWeight normal, bold
|
||||
New-HTMLList -Type Unordered {
|
||||
& $Script:GPOConfiguration['NetLogon']['List']
|
||||
} -FontSize 10pt
|
||||
#New-HTMLText -FontSize 10pt -Text 'Those problems must be resolved before doing other clenaup activities.'
|
||||
New-HTMLChart {
|
||||
New-ChartPie -Name 'Correct Owners' -Value $NetLogonOwnersAdministrators.Count -Color LightGreen
|
||||
New-ChartPie -Name 'Incorrect Owners' -Value $NetLogonOwnersToFix.Count -Color Crimson
|
||||
} -Title 'NetLogon Owners' -TitleAlignment center
|
||||
}
|
||||
New-HTMLPanel {
|
||||
}
|
||||
} -Online -ShowHTML:(-not $HideHTML) -FilePath $FilePath
|
||||
$TimeLogEndHTML = Stop-TimeLog -Time $TimeLogHTML -Option OneLiner
|
||||
Write-Color -Text '[i]', '[HTML ] ', 'Generating HTML report', " [Time to execute: $TimeLogEndHTML]" -Color Yellow, DarkGray, Yellow, DarkGray
|
||||
if ($PassThru) {
|
||||
$Script:Reporting
|
||||
}
|
||||
Reset-GPOZaurrStatus # This makes sure types are at it's proper status
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOList' -or $null -eq $Type) {
|
||||
New-HTMLTab -Name 'Group Policies Summary' {
|
||||
New-HTMLPanel {
|
||||
$newHTMLTextSplat = @{
|
||||
Text = @(
|
||||
'Following table shows a list of group policies.',
|
||||
'By using following table you can easily find which GPOs can be safely deleted because those are empty or unlinked or linked, but link disabled.'
|
||||
)
|
||||
FontSize = '10pt'
|
||||
FontWeight = 'normal', 'bold'
|
||||
}
|
||||
New-HTMLText @newHTMLTextSplat
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies total: ', $GPOTotal -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies valid: ", $GPOValid.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies to delete: ", $GPOEmptyOrUnlinked.Count -FontWeight normal, bold {
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies that are unlinked (are not doing anything currently): ', $GPONotLinked.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are empty (have no settings): ", $GPOEmpty.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are linked, but empty: ", $GPOLinkedButEmpty.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that are linked, but link disabled: ", $GPOLinkedButLinkDisabled.Count -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text 'All those mentioned Group Policies can be automatically deleted following the steps below the table.' -FontSize 10pt
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policies List' {
|
||||
New-HTMLTable -DataTable $GPOSummary -Filtering {
|
||||
New-HTMLTableCondition -Name 'Empty' -Value $true -BackgroundColor Salmon -TextTransform capitalize -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'Linked' -Value $false -BackgroundColor Salmon -TextTransform capitalize -ComparisonType string
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
New-HTMLSection -Name 'Steps to fix - Empty & Unlinked Group Policies' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLText -Text 'Following steps will guide you how to remove empty or unlinked group policies'
|
||||
New-HTMLWizard {
|
||||
& $Script:GPOConfiguration['GPOList']['Wizard']
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOOrphans' -or $null -eq $Type) {
|
||||
New-HTMLTab -Name 'Health State' {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -TextBlock {
|
||||
"Following table shows list of all group policies and their status in AD and SYSVOL. Due to different reasons it's "
|
||||
"possible that "
|
||||
} -FontSize 10pt
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies on SYSVOL, but no details in AD: ', $NotAvailableInAD.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Group Policies in AD, but no content on SYSVOL: ', $NotAvailableOnSysvol.Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which couldn't be assed due to permissions issue: ", $NotAvailablePermissionIssue.Count -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text "Follow the steps below table to get Active Directory Group Policies in healthy state." -FontSize 10pt
|
||||
}
|
||||
New-HTMLSection -Name 'Health State of Group Policies' {
|
||||
New-HTMLTable -DataTable $GPOOrphans -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 "Permissions issue" -BackgroundColor MediumVioletRed -ComparisonType string -Color White
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
New-HTMLSection -Name 'Steps to fix - Not available on SYSVOL / Active Directory' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLText -Text 'Following steps will guide you how to fix GPOs which are not available on SYSVOL or AD.'
|
||||
New-HTMLWizard {
|
||||
& $Script:GPOConfiguration['GPOOrphans']['Wizard']
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'NetLogon' -or $Type -contains 'GPOFiles' -or $null -eq $Type) {
|
||||
New-HTMLTab -Name 'Files (SysVol / NetLogon)' {
|
||||
if ($Type -contains 'NetLogon' -or $null -eq $Type) {
|
||||
New-HTMLTab -Name 'NetLogon Owners' {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -TextBlock {
|
||||
"Following table shows NetLogon file owners. It's important that NetLogon file owners are set to BUILTIN\Administrators (SID: S-1-5-32-544). "
|
||||
"Owners have full control over the file object. Current owner of the file may be an Administrator but it doesn't guarentee that he will be in the future. "
|
||||
"That's why as a best-practice it's recommended to change any non-administrative owners to BUILTIN\Administrators, and even Administrative accounts should be replaced with it. "
|
||||
} -FontSize 10pt
|
||||
New-HTMLList -Type Unordered {
|
||||
& $Script:GPOConfiguration['NetLogon']['List']
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text "Follow the steps below table to get NetLogon Owners into compliant state." -FontSize 10pt
|
||||
}
|
||||
New-HTMLSection -Name 'NetLogon Files List' {
|
||||
New-HTMLTable -DataTable $NetLogonOwners -Filtering {
|
||||
New-HTMLTableCondition -Name 'PrincipalSid' -Value "S-1-5-32-544" -BackgroundColor LightGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'PrincipalSid' -Value "S-1-5-32-544" -BackgroundColor Salmon -ComparisonType string -Operator ne
|
||||
New-HTMLTableCondition -Name 'PrincipalType' -Value "WellKnownAdministrative" -BackgroundColor LightGreen -ComparisonType string -Operator eq
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Steps to fix NetLogon Owners ' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLText -Text 'Following steps will guide you how to fix NetLogon Owners and make them compliant.'
|
||||
New-HTMLWizard {
|
||||
& $Script:GPOConfiguration['NetLogon']['Wizard']
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
New-HTMLTab -Name 'NetLogon Permissions' {
|
||||
New-HTMLSection -Name 'NetLogon Files List' {
|
||||
New-HTMLTable -DataTable $Netlogon -Filtering
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOFiles' -or $null -eq $Type) {
|
||||
New-HTMLTab -Name 'SysVol Files Assesment' {
|
||||
New-HTMLTable -DataTable $GPOFiles -Filtering
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOPermissionsRoot' -or $Type -contains 'GPOOwners' -or
|
||||
$Type -contains 'GPOPermissions' -or $Type -contains 'GPOConsistency' -or
|
||||
$null -eq $Type
|
||||
) {
|
||||
New-HTMLTab -Name 'Permissions' {
|
||||
if ($Type -contains 'GPOPermissionsRoot' -or $null -eq $Type) {
|
||||
New-HTMLTab -Name 'Root' {
|
||||
New-HTMLTable -DataTable $GPOPermissionsRoot -Filtering
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOOwners' -or $null -eq $Type) {
|
||||
New-HTMLTab -Name 'Owners' {
|
||||
if ($Script:GpoZaurrOwners['Solution']) {
|
||||
& $Script:GpoZaurrOwners['Solution']
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOPermissions' -or $null -eq $Type) {
|
||||
New-HTMLTab -Name 'Edit & Modify' {
|
||||
New-HTMLTable -DataTable $GPOPermissions -Filtering
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOConsistency' -or $null -eq $Type) {
|
||||
New-HTMLTab -Name 'Permissions Consistency' {
|
||||
New-HTMLPanel {
|
||||
New-HTMLText -Text 'Following table presents ', 'permissions consistency between Active Directory and SYSVOL for Group Policies' -FontSize 10pt -FontWeight normal, bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Top level permissions consistency: ', $Inconsistent[0].Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Inherited permissions consistency: ', $InconsistentInside[0].Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Inconsistent top level permissions: ', $Inconsistent[1].Count -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Inconsistent inherited permissions: ", $InconsistentInside[1].Count -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text 'Having incosistent permissions on AD in comparison to those on SYSVOL can lead to uncontrolled ability to modify them. Please notice that if ', `
|
||||
' Not available ', 'is visible in the table you should first fix related, more pressing issue, before fixing permissions inconsistency.' -FontWeight normal, bold, normal
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policy Permissions Consistency' {
|
||||
New-HTMLTable -DataTable $GPOPermissionsConsistency -Filtering {
|
||||
New-HTMLTableCondition -Name 'ACLConsistent' -Value $false -BackgroundColor Salmon -TextTransform capitalize -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ACLConsistentInside' -Value $false -BackgroundColor Salmon -TextTransform capitalize -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ACLConsistent' -Value $true -BackgroundColor PaleGreen -TextTransform capitalize -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ACLConsistentInside' -Value $true -BackgroundColor PaleGreen -TextTransform capitalize -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ACLConsistent' -Value 'Not available' -BackgroundColor Crimson -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'ACLConsistentInside' -Value 'Not available' -BackgroundColor Crimson -ComparisonType string
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
New-HTMLSection -Name 'Steps to fix - Permissions Consistency' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLText -Text 'Following steps will guide you how to fix permissions consistency'
|
||||
New-HTMLWizard {
|
||||
& $Script:GPOConfiguration['GPOConsistency']['Wizard']
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Type -contains 'GPOAnalysis' -or $null -eq $Type) {
|
||||
New-HTMLTab -Name 'Analysis' {
|
||||
foreach ($Key in $GPOContent.Keys) {
|
||||
New-HTMLTab -Name $Key {
|
||||
New-HTMLTable -DataTable $GPOContent[$Key] -Filtering -Title $Key
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} -Online -ShowHTML -FilePath $FilePath
|
||||
}
|
||||
[scriptblock] $SourcesAutoCompleter = {
|
||||
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
|
||||
|
||||
$Script:GPOConfiguration.Keys | Sort-Object | Where-Object { $_ -like "*$wordToComplete*" }
|
||||
}
|
||||
|
||||
Register-ArgumentCompleter -CommandName Invoke-GPOZaurr -ParameterName Type -ScriptBlock $SourcesAutoCompleter
|
||||
@@ -0,0 +1,19 @@
|
||||
function Optimize-GPOZaurr {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
|
||||
)
|
||||
|
||||
$GPOS = Get-GPOZaurr -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
foreach ($GPO in $GPOS) {
|
||||
if ($GPO.UserSettingsAvailable -eq $false -and $GPO.ComputerSettingsAvailable -eq $false) {
|
||||
if ($GPO.Enabled -ne 'All setttings disabled') {
|
||||
# $GPO
|
||||
}
|
||||
} elseif ($GPO.UserSettingsAvailable -eq $false) {
|
||||
|
||||
} elseif ($GPO.ComputerSettingsAvailable -eq $false) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
function Remove-GPOZaurrDuplicateObject {
|
||||
[cmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[int] $LimitProcessing = [int32]::MaxValue,
|
||||
[alias('ForestName')][string] $Forest,
|
||||
[string[]] $ExcludeDomains,
|
||||
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation
|
||||
)
|
||||
|
||||
$getGPOZaurrDuplicateObjectSplat = @{
|
||||
Forest = $Forest
|
||||
IncludeDomains = $IncludeDomains
|
||||
ExcludeDomains = $ExcludeDomains
|
||||
ExtendedForestInformation = $ExtendedForestInformation
|
||||
}
|
||||
|
||||
$DuplicateGpoObjects = Get-GPOZaurrDuplicateObject @getGPOZaurrDuplicateObjectSplat
|
||||
foreach ($Duplicate in $DuplicateGpoObjects | Select-Object -First $LimitProcessing) {
|
||||
try {
|
||||
Remove-ADObject -Identity $Duplicate.ObjectGUID -Recursive -ErrorAction Stop -Server $Duplicate.DomainName
|
||||
} catch {
|
||||
Write-Warning "Remove-GPOZaurrDuplicateObject - Deleting $($Duplicate.ConflictDN) / $($Duplicate.DomainName) via GUID: $($Duplicate.ObjectGUID) failed with error: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,12 +49,27 @@ That's it. Whenever there's a new version, you run the command, and you can enjo
|
||||
|
||||
## Changelog
|
||||
|
||||
- 0.0.70
|
||||
- 0.0.76 - 8.11.2020
|
||||
- Improved `Get-GPOZaurrNetLogon` to better handle errors
|
||||
- 0.0.75 - 8.11.2020
|
||||
- Improved `Get-GPOZaurrPermissionConsistency` to stop checking consistency if path doesn't exists
|
||||
- 0.0.74 - 8.11.2020
|
||||
- Improved `Invoke-GPOZaurr` (WIP)
|
||||
- 0.0.73 - 7.11.2020
|
||||
- Improved `Invoke-GPOZaurr` (WIP)
|
||||
- Improved `Get-GPOZaurr`
|
||||
- 0.0.72 - 6.11.2020
|
||||
- Improved `Invoke-GPOZaurr` (WIP)
|
||||
- 0.0.71 - 3.11.2020
|
||||
- Improved `Invoke-GPOZaurr` (WIP)
|
||||
- 0.0.70 - 29.10.2020
|
||||
- Added `Get-GPOZaurrDuplicateObject`
|
||||
- Added `Remove-GPOZaurrDuplicateObject`
|
||||
- 0.0.69 - 29.10.2020
|
||||
- Improved `Invoke-GPOZaurr` (WIP)
|
||||
- Improved `Get-GPOZaurrNetLogon`
|
||||
- Improved `Get-GPOZaurrOwner`
|
||||
- Improved `Set-GPOZaurrOwner`
|
||||
- 0.0.69 - 28.10.2020
|
||||
- Added `Repair-GPOZaurrNetLogonOwner`
|
||||
- Improved `Invoke-GPOZaurr` (WIP)
|
||||
- 0.0.68 - 28.10.2020
|
||||
|
||||
Reference in New Issue
Block a user