From 13e5672b3fb60b0e1028665c97e535b4d2bbbef0 Mon Sep 17 00:00:00 2001 From: Przemyslaw Klys Date: Mon, 19 Oct 2020 10:38:55 +0200 Subject: [PATCH] Update --- GPOZaurr.psd1 | 2 +- Private/Test-SysvolFolders.ps1 | 70 ++++++------- Public/Show-GPOZaurr.ps1 | 175 ++++++++++++++++++++------------- README.md | 1 + 4 files changed, 143 insertions(+), 105 deletions(-) diff --git a/GPOZaurr.psd1 b/GPOZaurr.psd1 index 5e21274..49b2561 100644 --- a/GPOZaurr.psd1 +++ b/GPOZaurr.psd1 @@ -6,7 +6,7 @@ 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-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-GPOZaurrSysvol', 'Get-GPOZaurrSysvolDFSR', 'Get-GPOZaurrWMI', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrPermission', 'Invoke-GPOZaurrSupport', 'New-GPOZaurrWMI', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrFolders', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrOrphaned', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Set-GPOOwner', 'Set-GPOZaurrOwner', 'Show-GPOZaurr') + FunctionsToExport = @('Add-GPOPermission', 'Add-GPOZaurrPermission', 'Backup-GPOZaurr', 'Clear-GPOZaurrSysvolDFSR', 'ConvertFrom-CSExtension', 'Find-CSExtension', 'Get-GPOZaurr', 'Get-GPOZaurrAD', 'Get-GPOZaurrBackupInformation', '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-GPOZaurrSysvol', 'Get-GPOZaurrSysvolDFSR', 'Get-GPOZaurrWMI', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrPermission', 'Invoke-GPOZaurrSupport', 'New-GPOZaurrWMI', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrFolders', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrOrphaned', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Set-GPOOwner', 'Set-GPOZaurrOwner', 'Show-GPOZaurr') GUID = 'f7d4c9e4-0298-4f51-ad77-e8e3febebbde' ModuleVersion = '0.0.63' PowerShellVersion = '5.1' diff --git a/Private/Test-SysvolFolders.ps1 b/Private/Test-SysvolFolders.ps1 index 4c26ea2..4a96452 100644 --- a/Private/Test-SysvolFolders.ps1 +++ b/Private/Test-SysvolFolders.ps1 @@ -5,14 +5,15 @@ [string] $Server, [string] $Domain, [System.Collections.IDictionary] $PoliciesAD, - $PoliciesSearchBase + [string] $PoliciesSearchBase ) $Differences = @{ } $SysvolHash = @{ } $GPOGUIDS = $GPOs.ID.GUID + $SysVolPath = "\\$($Server)\SYSVOL\$Domain\Policies" try { - $SYSVOL = Get-ChildItem -Path "\\$($Server)\SYSVOL\$Domain\Policies" -ErrorAction Stop + $SYSVOL = Get-ChildItem -Path "\\$($Server)\SYSVOL\$Domain\Policies" -Exclude 'PolicyDefinitions' -ErrorAction Stop } catch { $Sysvol = $Null } @@ -59,7 +60,10 @@ $ErrorMessage = $_.Exception.Message } } else { + $FullPath = -join ($SysVolPath, "\{$($GPO.Id.Guid)}") $ACL = $null + $Owner = '' + $ErrorMessage = 'Not found on SYSVOL' } if ($null -eq $Differences[$GPO.Id.Guid]) { $SysVolStatus = 'Unknown Issue' @@ -90,39 +94,37 @@ # Now we need to list thru Sysvol files and fine those that do not exists as GPO and create dummy GPO objects to show orphaned gpos foreach ($_ in $Differences.Keys) { if ($Differences[$_] -in 'Not available in AD', 'Permissions issue') { - if ($SysvolHash[$_].BaseName -notcontains 'PolicyDefinitions') { - $FullPath = $SysvolHash[$_].FullName - try { - $ACL = Get-Acl -Path $FullPath -ErrorAction Stop - $Owner = $ACL.Owner - $ErrorMessage = '' - } catch { - Write-Warning "Get-GPOZaurrSysvol - ACL reading (2) failed for $FullPath with error: $($_.Exception.Message)" - $ACL = $null - $Owner = $null - $ErrorMessage = $_.Exception.Message - } + $FullPath = $SysvolHash[$_].FullName + try { + $ACL = Get-Acl -Path $FullPath -ErrorAction Stop + $Owner = $ACL.Owner + $ErrorMessage = '' + } catch { + Write-Warning "Get-GPOZaurrSysvol - ACL reading (2) failed for $FullPath with error: $($_.Exception.Message)" + $ACL = $null + $Owner = $null + $ErrorMessage = $_.Exception.Message + } - [PSCustomObject] @{ - DisplayName = $SysvolHash[$_].BaseName - Status = $Differences[$_] - DomainName = $Domain - SysvolServer = $Server - SysvolStatus = 'Exists' #$Differences[$GPO.Id.Guid] - GpoStatus = $Differences[$_] - Owner = '' - FileOwner = $Owner - Id = $_ - Path = $FullPath - DistinguishedName = -join ("CN={", $_, "},", $PoliciesSearchBase) - Description = $null - CreationTime = $SysvolHash[$_].CreationTime - ModificationTime = $SysvolHash[$_].LastWriteTime - UserVersion = $null - ComputerVersion = $null - WmiFilter = $null - Error = $ErrorMessage - } + [PSCustomObject] @{ + DisplayName = $SysvolHash[$_].BaseName + Status = $Differences[$_] + DomainName = $Domain + SysvolServer = $Server + SysvolStatus = 'Exists' #$Differences[$GPO.Id.Guid] + GpoStatus = $Differences[$_] + Owner = '' + FileOwner = $Owner + Id = $_ + Path = $FullPath + DistinguishedName = -join ("CN={", $_, "},", $PoliciesSearchBase) + Description = $null + CreationTime = $SysvolHash[$_].CreationTime + ModificationTime = $SysvolHash[$_].LastWriteTime + UserVersion = $null + ComputerVersion = $null + WmiFilter = $null + Error = $ErrorMessage } } } diff --git a/Public/Show-GPOZaurr.ps1 b/Public/Show-GPOZaurr.ps1 index a36e80b..a07814e 100644 --- a/Public/Show-GPOZaurr.ps1 +++ b/Public/Show-GPOZaurr.ps1 @@ -2,9 +2,11 @@ [cmdletBinding()] param( [string] $FilePath, - [ValidateSet('GPOList', 'GPOOrphans', 'NetLogon')][string[]] $Type + [ValidateSet( + 'GPOList', 'GPOOrphans', 'GPOPermissions', 'GPOPermissionsRoot', + 'GPOConsistency', 'GPOOwners', 'GPOAnalysis', 'NetLogon' + )][string[]] $Type ) - if ($Type -contains 'GPOList' -or $null -eq $Type) { Write-Verbose -Message "Show-GPOZaurr - Processing GPO List" $GPOSummary = Get-GPOZaurr @@ -12,38 +14,38 @@ $GPOEmpty = $GPOSummary.Where( { $_.Empty -eq $true, 'split' }) $GPOTotal = $GPOSummary.Count } - if ($Type -contains 'GPOOrphans' -or $null -eq $Type) { Write-Verbose -Message "Show-GPOZaurr - Processing GPO Sysvol" $GPOOrphans = Get-GPOZaurrSysvol } - - Write-Verbose -Message "Show-GPOZaurr - Processing GPO Permissions" - $GPOPermissions = Get-GPOZaurrPermission -Type All -IncludePermissionType GpoEditDeleteModifySecurity, GpoEdit, GpoCustom -IncludeOwner - - Write-Verbose -Message "Show-GPOZaurr - Processing GPO Permissions Consistency" - $GPOPermissionsConsistency = Get-GPOZaurrPermissionConsistency -Type All -VerifyInheritance - - Write-Verbose -Message "Show-GPOZaurr - Processing GPO Permissions Root" - $GPOPermissionsRoot = Get-GPOZaurrPermissionRoot - - Write-Verbose "Show-GPOZaurr - Processing GPO Owners" - $GPOOwners = Get-GPOZaurrOwner -IncludeSysvol - + if ($Type -contains 'GPOPermissions' -or $null -eq $Type) { + Write-Verbose -Message "Show-GPOZaurr - Processing GPO Permissions" + $GPOPermissions = Get-GPOZaurrPermission -Type All -IncludePermissionType GpoEditDeleteModifySecurity, GpoEdit, GpoCustom -IncludeOwner + } + if ($Type -contains 'GPOConsistency' -or $null -eq $Type) { + Write-Verbose -Message "Show-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 ($Type -contains 'GPOConsistency' -or $null -eq $Type) { + Write-Verbose -Message "Show-GPOZaurr - Processing GPO Permissions Root" + $GPOPermissionsRoot = Get-GPOZaurrPermissionRoot + } + if ($Type -contains 'GPOOwners' -or $null -eq $Type) { + Write-Verbose "Show-GPOZaurr - Processing GPO Owners" + $GPOOwners = Get-GPOZaurrOwner -IncludeSysvol + $IsOwnerConsistent = $GPOOwners.Where( { $_.IsOwnerConsistent -eq $true } , 'split' ) + $IsOwnerAdministrative = $GPOOwners.Where( { $_.IsOwnerAdministrative -eq $true } , 'split' ) + } if ($Type -contains 'NetLogon' -or $null -eq $Type) { Write-Verbose "Get-GPOZaurrNetLogon - Processing NETLOGON Share" $Netlogon = Get-GPOZaurrNetlogon } - Write-Verbose "Show-GPOZaurr - Processing GPO Analysis" - $GPOContent = Invoke-GPOZaurr - - - - $IsOwnerConsistent = $GPOOwners.Where( { $_.IsOwnerConsistent -eq $true } , 'split' ) - $IsOwnerAdministrative = $GPOOwners.Where( { $_.IsOwnerAdministrative -eq $true } , 'split' ) - - [Array] $Inconsistent = $GPOPermissionsConsistency.Where( { $_.ACLConsistent -eq $true } , 'split' ) - [Array] $InconsistentInside = $GPOPermissionsConsistency.Where( { $_.ACLConsistentInside -eq $true }, 'split' ) + if ($Type -contains 'GPOAnalysis' -or $null -eq $Type) { + Write-Verbose "Show-GPOZaurr - Processing GPO Analysis" + $GPOContent = Invoke-GPOZaurr + } Write-Verbose "Show-GPOZaurr - Generating HTML" New-HTML { @@ -51,49 +53,64 @@ New-HTMLSectionStyle -BorderRadius 0px -HeaderBackGroundColor Grey -RemoveShadow New-HTMLTableOption -DataStore JavaScript New-HTMLTab -Name 'Overview' { - New-HTMLSection -Invisible { - New-HTMLPanel { - New-HTMLChart -Title 'Group Policies Summary' { - New-ChartLegend -Names 'Unlinked', 'Linked', 'Empty', 'Total' -Color Salmon, PaleGreen, PaleVioletRed, PaleTurquoise - New-ChartBar -Name 'Group Policies' -Value $GPOLinked[1].Count, $GPOLinked[0].Count, $GPOEmpty[1].Count, $GPOTotal - } -TitleAlignment center - } - New-HTMLPanel { - New-HTMLChart { - 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 - } -Title 'Permissions Consistency' -TitleAlignment center + 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-HTMLChart -Title 'Group Policies Summary' { + New-ChartLegend -Names 'Unlinked', 'Linked', 'Empty', 'Total' -Color Salmon, PaleGreen, PaleVioletRed, PaleTurquoise + New-ChartBar -Name 'Group Policies' -Value $GPOLinked[1].Count, $GPOLinked[0].Count, $GPOEmpty[1].Count, $GPOTotal + } -TitleAlignment center + } + } + if ($Type -contains 'GPOConsistency' -or $null -eq $Type) { + New-HTMLPanel { + New-HTMLChart { + 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 + } -Title 'Permissions Consistency' -TitleAlignment center + } + } } } - New-HTMLSection -Invisible { - 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)." - New-HTMLChart { - New-ChartBarOptions -Type barStacked - New-ChartLegend -Name 'Yes', 'No' -Color PaleGreen, Orchid - New-ChartBar -Name 'Is administrative' -Value $IsOwnerAdministrative[0].Count, $IsOwnerAdministrative[1].Count - New-ChartBar -Name 'Is consistent' -Value $IsOwnerConsistent[0].Count, $IsOwnerConsistent[1].Count - } -Title 'Group Policy Owners' - } - New-HTMLPanel { + if ($Type -contains 'GPOOwners' -or $Type -contains 'GPOOwners' -or $null -eq $Type) { + New-HTMLSection -Invisible { + if ($Type -contains 'GPOOwners' -or $null -eq $Type) { + 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)." + New-HTMLChart { + New-ChartBarOptions -Type barStacked + New-ChartLegend -Name 'Yes', 'No' -Color PaleGreen, Orchid + New-ChartBar -Name 'Is administrative' -Value $IsOwnerAdministrative[0].Count, $IsOwnerAdministrative[1].Count + New-ChartBar -Name 'Is consistent' -Value $IsOwnerConsistent[0].Count, $IsOwnerConsistent[1].Count + } -Title 'Group Policy Owners' + } + } + if ($Type -contains 'GPOOwners' -or $null -eq $Type) { + New-HTMLPanel { + } + } } } } if ($Type -contains 'GPOList' -or $null -eq $Type) { New-HTMLTab -Name 'Group Policies Summary' { New-HTMLTable -DataTable $GPOSummary -Filtering { - New-HTMLTableCondition -Name 'Empty' -Value $false -BackgroundColor Salmon -TextTransform capitalize -ComparisonType bool + New-HTMLTableCondition -Name 'Empty' -Value $true -BackgroundColor Salmon -TextTransform capitalize -ComparisonType bool New-HTMLTableCondition -Name 'Linked' -Value $false -BackgroundColor Salmon -TextTransform capitalize -ComparisonType bool } } } if ($Type -contains 'GPOOrphans' -or $null -eq $Type) { New-HTMLTab -Name 'Sysvol' { - New-HTMLTable -DataTable $GPOOrphans -Filtering + 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 Salmon -ComparisonType string + } } } if ($Type -contains 'NetLogon' -or $null -eq $Type) { @@ -101,24 +118,42 @@ New-HTMLTable -DataTable $Netlogon -Filtering } } - New-HTMLTab -Name 'Permissions' { - New-HTMLTab -Name 'Root' { - New-HTMLTable -DataTable $GPOPermissionsRoot -Filtering - } - New-HTMLTab -Name 'Owners' { - New-HTMLTable -DataTable $GPOOwners -Filtering - } - New-HTMLTab -Name 'Edit & Modify' { - New-HTMLTable -DataTable $GPOPermissions -Filtering - } - New-HTMLTab -Name 'Inconsistent' { - New-HTMLTable -DataTable $GPOPermissionsConsistency -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' { + New-HTMLTable -DataTable $GPOOwners -Filtering + } + } + 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-HTMLTable -DataTable $GPOPermissionsConsistency -Filtering { + New-HTMLTableCondition -Name 'ACLConsistent' -Value $false -BackgroundColor Salmon -TextTransform capitalize -ComparisonType bool + New-HTMLTableCondition -Name 'ACLConsistentInside' -Value $false -BackgroundColor Salmon -TextTransform capitalize -ComparisonType bool + } + } + } } } - New-HTMLTab -Name 'Analysis' { - foreach ($Key in $GPOContent.Keys) { - New-HTMLTab -Name $Key { - New-HTMLTable -DataTable $GPOContent[$Key] -Filtering -Title $Key + 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 + } } } } diff --git a/README.md b/README.md index ee44365..be83087 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ That's it. Whenever there's a new version, you run the command, and you can enjo - Added `OutputType`,`OutputType`,`Open`,`Online` parameters to `Invoke-GPOZaurr` - Added `Get-GPOZaurrNetLogon` - Improved `Get-GPOZaurrOwner` + - Fixes `Get-GPOZaurrSysvol` - 0.0.62 - 14.10.2020 - Renamed `Invoke-GPOZaurr` to `Invoke-GPOZaurrContent` - I want to use `Invoke-GPOZaurr` for something else - Improvements to `Get-GPOZaurrPermissionConsistency` for GPOs without SYSVOL to be reported properly