mirror of
https://github.com/EvotecIT/GPOZaurr.git
synced 2026-07-26 20:00:09 +00:00
Compare commits
249 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d15363caa | |||
| 6c62a11767 | |||
| 61bfe5bd4d | |||
| 5043767e8d | |||
| e4ecafaea5 | |||
| 154e3428e6 | |||
| a6c2ac1226 | |||
| 2b0a395abc | |||
| 04b7242bde | |||
| 48af562bfd | |||
| a5d447b28c | |||
| e649a489bc | |||
| bf3cfb8d21 | |||
| f250453536 | |||
| 34902ab6d8 | |||
| ddaadf56a3 | |||
| 25805e5199 | |||
| e0fe437e1e | |||
| c282fcc784 | |||
| a8f496190d | |||
| 4f41a98e89 | |||
| 010c4dc8e0 | |||
| db57b9ee22 | |||
| b7315b0fa5 | |||
| 8b9c9e66b8 | |||
| 5a2f789321 | |||
| b3023051f3 | |||
| 9538facc13 | |||
| 7c914d8134 | |||
| 90f951d995 | |||
| b2db6d5662 | |||
| cafd3f7938 | |||
| ba81950eed | |||
| 810ef18baa | |||
| dbf99debee | |||
| 4cd644d1b4 | |||
| e2aa7af83d | |||
| ff1668c60d | |||
| 5f82bbaea4 | |||
| 75cee65b65 | |||
| 0dc56d314e | |||
| 9c689708ba | |||
| bb18d488b4 | |||
| e72d81aee3 | |||
| 70ed52cdf9 | |||
| 3b414e712c | |||
| 7ed1410fd9 | |||
| 6d2e476916 | |||
| b7ed5e0c5a | |||
| 72bd69d0e6 | |||
| b5c1f3dcd5 | |||
| bc773e2e83 | |||
| 8db961cba6 | |||
| 227639d0f6 | |||
| e03f819461 | |||
| fb955f645b | |||
| 3fc3b74798 | |||
| 695f4dbe6a | |||
| 5d69cef128 | |||
| 062374b4be | |||
| e61329ac66 | |||
| d3328dbb81 | |||
| 5803371b5e | |||
| 263f364ede | |||
| 16a181155b | |||
| 962d8829d7 | |||
| 4155c35cc6 | |||
| 614d8cbda5 | |||
| 43e7f2e746 | |||
| 9a3ed3b6ce | |||
| 50f0cfc1a6 | |||
| 269d611563 | |||
| 55ab89a5b0 | |||
| 9da8c7c94b | |||
| 53aa69029f | |||
| 4189ad12f2 | |||
| b1c3037803 | |||
| 62308cbb6d | |||
| 914dcfb0c4 | |||
| 2cf4d2c6c9 | |||
| d53d50f99b | |||
| 2ef3c306ff | |||
| 481338f83b | |||
| eaf3b231ae | |||
| b2c73479c7 | |||
| 38c6327e30 | |||
| 0b3e072a3e | |||
| 89664bfd02 | |||
| 1021ebe5f4 | |||
| 521125bbc1 | |||
| ae6b596e5b | |||
| bfe50f02fe | |||
| 187b44a19d | |||
| 36793b33c4 | |||
| 94e6c785c1 | |||
| efbd2b12de | |||
| d0a678353f | |||
| 6b0f3b332d | |||
| 37483c91b5 | |||
| 9172948be3 | |||
| 14567959f7 | |||
| 6a9ad14083 | |||
| e00de40cd2 | |||
| 6f806698e9 | |||
| 2e1571b0d7 | |||
| ffedd2d9d2 | |||
| 911bc50f22 | |||
| 0383d249e9 | |||
| 8070179d27 | |||
| db67e6191e | |||
| db9b6d60c6 | |||
| 2c965d81d5 | |||
| bff372affe | |||
| 138a0f411e | |||
| 1c37a9d1df | |||
| 30535c1baf | |||
| 56c722edd0 | |||
| 1f43ae21fe | |||
| ef90ef05f7 | |||
| 43b304d252 | |||
| 24e691edb9 | |||
| 1c787735d4 | |||
| 13a2aa6482 | |||
| 1ac1f83abd | |||
| 65b2867588 | |||
| 1043a2d512 | |||
| 7002813027 | |||
| 03b8e4f2cb | |||
| 680762733e | |||
| 7a37d5b9f6 | |||
| a1e9a4a3fa | |||
| 8cbb3272b2 | |||
| 8da0c1793d | |||
| 5a7b20ca2b | |||
| ebffba3b95 | |||
| a79071c395 | |||
| a5a889b468 | |||
| 62d73041ea | |||
| d88307047c | |||
| 7d85d41747 | |||
| a1fab2ceb2 | |||
| 99f07f61e3 | |||
| 58136f0c43 | |||
| b55729d8e0 | |||
| 6206a33a2e | |||
| 165381b1e3 | |||
| ea1de10fd9 | |||
| 03453b6bdb | |||
| 4d7f49902d | |||
| 508d778d06 | |||
| 5c3157f15f | |||
| b33f42b320 | |||
| f8d3b363e7 | |||
| a68d917d19 | |||
| 946bb3029f | |||
| 975bf5b889 | |||
| 6fa0818375 | |||
| 2abec9579a | |||
| 75a8083368 | |||
| 06c711694e | |||
| 8a38ac4556 | |||
| 9d2ae288c0 | |||
| 0bc50328ee | |||
| a74b662c9b | |||
| 37d8db92f7 | |||
| d094344f9f | |||
| a24b1ff958 | |||
| de076a1cb4 | |||
| 663eecc01b | |||
| d1b7d71ad9 | |||
| d888f135e0 | |||
| 81ecf580c4 | |||
| 34c9d59150 | |||
| 80580b7dce | |||
| 304f70a4d9 | |||
| ab6c61ac52 | |||
| dbe79a7833 | |||
| 0cc05c4aeb | |||
| c10a4c088e | |||
| 015afd69a4 | |||
| 2fa9b202bc | |||
| 25bbf8d52e | |||
| 8a009bf288 | |||
| ed76fc9513 | |||
| 646c22bdab | |||
| d4f8cdc8e8 | |||
| 166d4fb767 | |||
| 0ca98a4165 | |||
| a5bcbbf285 | |||
| 513179fd03 | |||
| 72cd1da9ae | |||
| 3fe52c99b5 | |||
| fc6fe14579 | |||
| bd5a73439d | |||
| 469332e543 | |||
| 6cbe3a375a | |||
| c987ca9863 | |||
| f0d24e1902 | |||
| 61b9c916e7 | |||
| deebcb825d | |||
| 7adfd1ef65 | |||
| 828c221ac9 | |||
| 8e80fd423d | |||
| f52fd60fef | |||
| 9594afb246 | |||
| 7c52284b48 | |||
| 2fd64952af | |||
| 15538e8559 | |||
| a36a470538 | |||
| 0a5d65761c | |||
| 7ed3cb6dad | |||
| 4d9edde212 | |||
| 7ba40e3981 | |||
| ec81655019 | |||
| 752a34204b | |||
| 0afe6c6d23 | |||
| 2a300747a1 | |||
| 94b8a71192 | |||
| 49b9eccfd1 | |||
| 92b5f00d7f | |||
| 1f625e4e90 | |||
| 7ac406ca24 | |||
| 4d584902e8 | |||
| 7e6efb81f1 | |||
| 16b0a0f4b6 | |||
| 85eaa4e5d6 | |||
| 8c555a4fa9 | |||
| 8bc85a4c91 | |||
| 84ad1df972 | |||
| 71a12316e3 | |||
| 4a3a49440f | |||
| 0b2e2ea96c | |||
| 4ae3bbce12 | |||
| 471bc04fb2 | |||
| 4d050c536d | |||
| 508402b4bf | |||
| 6f1ac33df8 | |||
| 5130ef77e5 | |||
| 19c2b6bf90 | |||
| 5b1aaae915 | |||
| d239c979e9 | |||
| 35c04c88c0 | |||
| 048347c830 | |||
| 563ba55342 | |||
| 5a62968925 | |||
| a47fa85a8c | |||
| b156c91c7c | |||
| d44e27e68c | |||
| e5dc00007f |
@@ -1,4 +1,4 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$T = Get-GPOZaurrPermission -Type Unknown -Verbose
|
||||
$T | Out-HtmlView -ScrollX -Filtering -DisablePaging -ScrollY -Online
|
||||
$T #| Out-HtmlView #-ScrollX -Filtering -DisablePaging -ScrollY -Online
|
||||
@@ -1,11 +1,11 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
# Step 1 - Create report
|
||||
$Report = Get-GPOZaurrPermission -Type All
|
||||
$Report | ConvertTo-Excel -FilePath $Env:UserProfile\Desktop\GPOOutput.xlsx -ExcelWorkSheetName 'GPO Permissions Before' -AutoFilter -AutoFit
|
||||
#$Report = Get-GPOZaurrPermission -Type All
|
||||
#$Report | ConvertTo-Excel -FilePath $Env:UserProfile\Desktop\GPOOutput.xlsx -ExcelWorkSheetName 'GPO Permissions Before' -AutoFilter -AutoFit
|
||||
|
||||
# Step 2 - Verify couple of GPOS returned with whatif
|
||||
#Remove-GPOZaurrPermission -Verbose -Type Unknown -LimitProcessing 4 -WhatIf
|
||||
Remove-GPOZaurrPermission -Verbose -Type Unknown -LimitProcessing 4 -WhatIf
|
||||
|
||||
# Step 3 - Confirm the change without whatif
|
||||
#Remove-GPOZaurrPermission -Verbose -Type Unknown -LimitProcessing 4
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# regardless if current user is still Domain Admin or not
|
||||
|
||||
$GPOs = Get-GPOZaurrOwner -IncludeSysvol
|
||||
$GPOs | Format-Table DisplayName, Owner, OwnerSID, OwnerType, SysvolOwner, SysvolSID, SysvolType
|
||||
$GPOs | Format-Table DisplayName, Status, Owner, OwnerSID, OwnerType, SysvolOwner, SysvolSID, SysvolType
|
||||
|
||||
Set-GPOZaurrOwner -Type Unknown -Verbose -WhatIf #-LimitProcessing 2
|
||||
Set-GPOZaurrOwner -Type All -Verbose -LimitProcessing 2 -WhatIf -IncludeDomains 'ad.evotec.pl'
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$GPOs = Get-GPOZaurrOwner -IncludeSysvol -Verbose
|
||||
$GPOs | Format-Table DisplayName, Status, Owner, OwnerSID, OwnerType, SysvolOwner, SysvolSID, SysvolType
|
||||
|
||||
#Set-GPOZaurrOwner -Type All -Verbose -LimitProcessing 2 -WhatIf -IncludeDomains 'ad.evotec.xyz'
|
||||
|
||||
Set-GPOZaurrOwner -Type All -Verbose -LimitProcessing 2 -WhatIf -IncludeDomains 'ad.evotec.xyz' -ApprovedOwner @(
|
||||
'EVOTEC\przemyslaw.klys'
|
||||
)
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
$T = Get-GPOZaurrOwner -Verbose -IncludeSysvol
|
||||
$T | Format-Table *
|
||||
#$T | Out-HtmlView -ScrollX
|
||||
|
||||
$T = Get-GPOZaurrOwner -Verbose -IncludeSysvol -ApprovedOwner @('EVOTEC\Domain Admins')
|
||||
$T | Format-Table *
|
||||
|
||||
$T = Get-GPOZaurrOwner -Verbose -IncludeSysvol -GPOName 'Default Domain Policy'
|
||||
$T | Format-Table *
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurrGPOOwners.html -Type GPOOwners -Online -Exclusions @(
|
||||
'EVOTEC\Domain Admins'
|
||||
'EVOTEC\przemyslaw.klys'
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$SummaryHashtable = Get-GPOZaurrLink -AsHashTable -Summary
|
||||
$SummaryHashtable | Format-Table -AutoSize
|
||||
$SummaryHashtable[5]
|
||||
@@ -1,3 +1,3 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Get-GPOZaurrLink | Format-Table -AutoSize *
|
||||
Get-GPOZaurrLink -Verbose | Format-Table -AutoSize *
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
Get-GPOZaurrLink -SearchBase 'OU=Domain Controllers,DC=ad,DC=evotec,DC=xyz' | Format-Table -AutoSize
|
||||
|
||||
Get-GPOZaurrLink -SearchBase 'OU=Computers,OU=Production,DC=ad,DC=evotec,DC=xyz' | Format-Table -AutoSize
|
||||
Get-GPOZaurrLink -SearchBase 'OU=Accounts,OU=Production,DC=ad,DC=evotec,DC=xyz' | Format-Table -AutoSize
|
||||
|
||||
Get-GPOZaurrLink -SearchBase 'DC=ad,DC=evotec,DC=xyz' -SearchScope Base | Format-Table -AutoSize
|
||||
@@ -1,6 +1,7 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Get-ADOrganizationalUnit -Filter * -Properties distinguishedName, LinkedGroupPolicyObjects | Get-GPOZaurrLink | Format-Table
|
||||
Get-ADOrganizationalUnit -Filter * -Properties canonicalname, distinguishedName, LinkedGroupPolicyObjects | Get-GPOZaurrLink | Format-Table
|
||||
# gpLink is required property. While LinkedGroupPolicyObjects does work it doesn't contain information about enabled/enforced GPO
|
||||
Get-ADOrganizationalUnit -Filter * -Properties distinguishedName, LinkedGroupPolicyObjects, gpLink | Get-GPOZaurrLink | Format-Table
|
||||
Get-ADOrganizationalUnit -Filter * -Properties canonicalname, distinguishedName, LinkedGroupPolicyObjects, gpLink | Get-GPOZaurrLink | Format-Table
|
||||
Get-ADObject -Filter * -Properties distinguishedName, gplink -Server 'ad.evotec.pl' | Get-GPOZaurrLink | Format-Table -AutoSize
|
||||
Get-GPOZaurrLink | Format-Table -AutoSize
|
||||
@@ -0,0 +1,3 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Get-GPOZaurrLink -Site 'Katowice-1','Katowice-2' | Format-Table -AutoSize *
|
||||
@@ -0,0 +1,3 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Get-GPOZaurrLink -Linked Site | Format-Table -AutoSize *
|
||||
@@ -0,0 +1,8 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$Summary = Get-GPOZaurrLink -Summary
|
||||
$Summary | Format-Table -AutoSize *
|
||||
|
||||
$OneGPO = $Summary | Where-Object { $_.DisplayName -eq 'ALL | Enable RDP' }
|
||||
$OneGPO.Links
|
||||
$OneGPO.LinksObjects | Format-Table *
|
||||
@@ -7,4 +7,7 @@ Add-GPOZaurrPermission -GPOName 'New Group Policy Object' -Type AuthenticatedUse
|
||||
Add-GPOZaurrPermission -Type AuthenticatedUsers -PermissionType GpoRead -All -WhatIf -Verbose
|
||||
|
||||
# Add Domain Admins/Enterprise Admins to all that need it
|
||||
Add-GPOZaurrPermission -Type Administrative -PermissionType GpoEditDeleteModifySecurity -All -WhatIf -Verbose
|
||||
Add-GPOZaurrPermission -Type Administrative -PermissionType GpoEditDeleteModifySecurity -All -WhatIf -Verbose
|
||||
|
||||
# Add ranom name to all that need it
|
||||
Add-GPOZaurrPermission -All -Principal SVC_AGPM -PrincipalType Name -PermissionType GpoEditDeleteModifySecurity -Verbose -LimitProcessing 2 -WhatIf
|
||||
@@ -0,0 +1,41 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Clear-Host
|
||||
|
||||
$GPOName = 'TEST | Deny Admins'
|
||||
|
||||
$T = Get-GPOZaurrPermission -GPOName $GPOName #-IncludePermissionType GpoEditDeleteModifySecurity -PermitType Allow -Principal 'Domain Admins' -PrincipalType 'Name'
|
||||
$T | Format-Table *
|
||||
|
||||
|
||||
return
|
||||
|
||||
<#
|
||||
# this will go and check for both Domain Admins / Enterprise Admins - if found won't do anything
|
||||
Add-GPOZaurrPermission -GPOName $GPOName -PermissionType GpoEditDeleteModifySecurity -Type Administrative -Verbose
|
||||
# this will go thru, because PrincipalType is not set to look by Name. Be precise with what you ask for
|
||||
Add-GPOZaurrPermission -GPOName $GPOName -PermissionType GpoEditDeleteModifySecurity -Principal 'Domain Admins' -Verbose
|
||||
# this will be detected as already existing
|
||||
Add-GPOZaurrPermission -GPOName $GPOName -PermissionType GpoEditDeleteModifySecurity -Principal 'Domain Admins' -PrincipalType Name -Verbose
|
||||
# this will be added only if it doesn't exists - assuming that przemyslaw.klys is displayed in Get-GPOZaurrPermissions
|
||||
Add-GPOZaurrPermission -GPOName $GPOName -PermissionType GpoApply -Principal 'przemyslaw.klys' -PrincipalType Name -Verbose
|
||||
# this will be added only if it doesn't exists - assuming that przemyslaw.klys is displayed in Get-GPOZaurrPermissions
|
||||
Add-GPOZaurrPermission -GPOName $GPOName -PermissionType GpoEditDeleteModifySecurity -Principal 'przemyslaw.klys' -PrincipalType Name -Verbose
|
||||
# this will ADD system if it doesn't eists
|
||||
Add-GPOZaurrPermission -GPOName $GPOName -PermissionType GpoEditDeleteModifySecurity -Type WellKnownAdministrative -Verbose
|
||||
|
||||
Add-GPOZaurrPermission -GPOName $GPOName -PermissionType GpoApply -Principal 'przemyslaw.klys' -Verbose
|
||||
Add-GPOZaurrPermission -GPOName $GPOName -PermissionType GpoEditDeleteModifySecurity -Principal 'przemyslaw.klys' -Verbose
|
||||
# this will not work because we already have GPOEditDeleteModifySecurity which is higher than GpoEDIT
|
||||
Add-GPOZaurrPermission -GPOName $GPOName -PermissionType GpoEdit -Principal 'przemyslaw.klys' -Verbose
|
||||
#>
|
||||
Add-GPOZaurrPermission -GPOName $GPOName -Type AuthenticatedUsers -PermissionType GpoRead -Verbose #-WhatIf
|
||||
|
||||
#$T = Get-GPOZaurrPermission -GPOName $GPOName #-ExcludePermissionType GpoApply,GpoRead -IncludeGPOObject
|
||||
#$T | Format-Table -AutoSize *
|
||||
|
||||
#Remove-GPOZaurrPermission -GPOName $GPOName -PermissionType GpoApply -Principal 'przemyslaw.klys' -PrincipalType Name -Verbose
|
||||
|
||||
#$T = Get-GPOZaurrPermission -GPOName $GPOName #-ExcludePermissionType GpoApply,GpoRead -IncludeGPOObject
|
||||
#$T = Get-GPOZaurrPermission -GPOName $GPOName #-ExcludePermissionType GpoApply,GpoRead -IncludeGPOObject
|
||||
#$T | Format-Table -AutoSize *
|
||||
@@ -9,4 +9,4 @@ Invoke-GPOZaurrPermission -Linked Root -Verbose {
|
||||
Remove-GPOPermission -Type NotAdministrative, NotWellKnownAdministrative -IncludePermissionType GpoEdit, GpoEditDeleteModifySecurity
|
||||
Add-GPOPermission -Type Administrative -IncludePermissionType GpoEditDeleteModifySecurity
|
||||
#Add-GPOPermission -Type WellKnownAdministrative -IncludePermissionType GpoEditDeleteModifySecurity
|
||||
} #-WhatIf #| Format-Table *
|
||||
} -WhatIf
|
||||
@@ -1,11 +1,11 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Invoke-GPOZaurrPermission -Verbose -SearchBase 'OU=Computers,OU=Production,DC=ad,DC=evotec,DC=xyz' {
|
||||
Invoke-GPOZaurrPermission -Verbose -SearchBase 'OU=Production,DC=ad,DC=evotec,DC=pl' {
|
||||
Set-GPOOwner -Type Administrative
|
||||
#Set-GPOOwner -Principal 'EVOTEC\Enterprise Admins'
|
||||
#Set-GPOOwner -Principal 'Domain Admins'
|
||||
#Remove-GPOPermission -Type Administrative -IncludePermissionType GPOCustom
|
||||
Remove-GPOPermission -Type NotAdministrative, NotWellKnownAdministrative -IncludePermissionType GpoEdit, GpoEditDeleteModifySecurity
|
||||
#Add-GPOPermission -Type Administrative -IncludePermissionType GpoEditDeleteModifySecurity
|
||||
#Add-GPOPermission -Type WellKnownAdministrative -IncludePermissionType GpoEditDeleteModifySecurity
|
||||
} -WhatIf #| Format-Table *
|
||||
Add-GPOPermission -Type Administrative -IncludePermissionType GpoEditDeleteModifySecurity
|
||||
Add-GPOPermission -Type WellKnownAdministrative -IncludePermissionType GpoEditDeleteModifySecurity
|
||||
} -WhatIf
|
||||
@@ -1,10 +1,10 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
# Find broken GPOs
|
||||
Get-GPOZaurrBroken -Verbose -IncludeDomains 'ad.evotec.pl' | Format-Table
|
||||
Get-GPOZaurrBroken -Verbose | Format-Table # -IncludeDomains 'ad.evotec.pl' | Format-Table
|
||||
|
||||
# this allows you to process X amount of orphaned folders/files (good for testing)
|
||||
Remove-GPOZaurrBroken -Verbose -WhatIf #-IncludeDomains 'ad.evotec.pl' #-LimitProcessing 2
|
||||
Remove-GPOZaurrBroken -Verbose -WhatIf -Type AD -LimitProcessing 10 #-IncludeDomains 'ad.evotec.pl' #-LimitProcessing 2
|
||||
|
||||
# this runs for whole SYSVOL and checks things against GPOS
|
||||
Remove-GPOZaurrBroken -Verbose -IncludeDomains 'ad.evotec.xyz' -BackupPath $Env:UserProfile\Desktop\MyBackup1 -WhatIf
|
||||
Remove-GPOZaurrBroken -Verbose -IncludeDomains 'ad.evotec.xyz' -BackupPath $Env:UserProfile\Desktop\MyBackup1 -WhatIf -Type AD, SYSVOL
|
||||
@@ -8,7 +8,7 @@ Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
#Get-GPOZaurrLinkSummary -Report 'LinksSummary' -UnlimitedProperties | Format-Table *
|
||||
|
||||
$Report = Get-GPOZaurrLinkSummary #-UnlimitedProperties
|
||||
$Report | Format-Table *
|
||||
$Report.MultipleLinks | Format-Table *
|
||||
#$Report | Format-Table
|
||||
#$Report.MultipleLinks | Format-Table *
|
||||
$Report.OneLink | Format-Table *
|
||||
$Report.LinksSummary | Format-Table *
|
||||
#$Report.LinksSummary | Format-Table *
|
||||
@@ -1,4 +1,4 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$Output = Invoke-GPOZaurrContent -Verbose -OutputType HTML, Object -Open
|
||||
$Output = Invoke-GPOZaurrContent -Verbose -OutputType HTML, Object -Open -GPOPath "C:\Support\GitHub\GpoZaurr\Ignore\NewExamples" ##-Type LocalGroups
|
||||
$Output | Format-Table
|
||||
@@ -1,4 +1,4 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$Policies = Get-GPOZaurrFilesPolicyDefinition -Signature
|
||||
$Policies | Format-Table
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
# Report on empty folders
|
||||
Get-GPOZaurrFolders -FolderType Empty | Format-Table *
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
# Cleanup based on https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/manually-clearing-the-conflictanddeleted-folder-in-dfsr/ba-p/395711
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Invoke-GPOZaurrSupport -ComputerName 'ad1.ad.evotec.xyz' -UserName 'EVOTEC\przemyslaw.klys' -Type NativeHTML -ForceGPResult -Verbose
|
||||
|
||||
#Invoke-GPOZaurrSupport -ComputerName 'ad1.ad.evotec.xyz' -UserName 'EVOTEC\przemyslaw.klys' -Type HTML -Verbose -Path $PSScriptRoot\Reports\GPOSupport.html
|
||||
Invoke-GPOZaurrSupport -Type HTML -Verbose -Path $PSScriptRoot\Reports\GPOSupport.html -ComputerName ad1.ad.evotec.xyz
|
||||
return
|
||||
#$Support1 = Invoke-GPOZaurrSupport -ComputerName 'AD1' -UserName 'przemyslaw.klys' -Type Object
|
||||
#$Support = Invoke-GPOZaurrSupport -ComputerName 'AD1' -UserName 'EVOTEC\Administrator' -Type Object
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
# Extracts CSE from registry
|
||||
$AllRegistryExtensions = Find-CSExtension
|
||||
|
||||
@@ -6,5 +6,10 @@
|
||||
|
||||
# Get same output DN, CanonicalName, BlockInheritance (True/False) + Users/Computers + UsersCount/ComputerCount for those with Blocked Inhertiance
|
||||
# This is so you can have a list what machines are affected
|
||||
$Objects = Get-GPOZaurrInheritance -IncludeBlockedObjects -OnlyBlockedInheritance
|
||||
$ExcludedOU = @(
|
||||
# Works on OU/
|
||||
'ad.evotec.xyz/ITR02/Test'
|
||||
)
|
||||
|
||||
$Objects = Get-GPOZaurrInheritance -IncludeBlockedObjects -IncludeExcludedObjects -OnlyBlockedInheritance -Exclusions $ExcludedOU -IncludeGroupPoliciesForBlockedObjects
|
||||
$Objects | Format-Table
|
||||
@@ -1,4 +1,4 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$FilesAll = Get-GPOZaurrNetLogon -SkipOwner -IncludeDomains 'ad.evotec.pl' #-OwnerOnly
|
||||
$FilesAll = Get-GPOZaurrNetLogon -IncludeDomains 'ad.evotec.xyz' -Verbose -OwnerOnly
|
||||
$FilesAll | Format-Table -a *
|
||||
@@ -1,7 +1,16 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$Output = Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type GPOOrphans -PassThru
|
||||
$Output
|
||||
#$Output = Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -PassThru -Type GPOConsistency, GPOList, GPODuplicates, GPOBroken, GPOOwners, NetLogonOwners, GPOPermissionsRead, GPOPermissionsAdministrative,GPOPermissionsUnknown
|
||||
|
||||
Write-Color -Text 'Output of nested report' -Color DarkYellow -LinesBefore 1 -LinesAfter 1
|
||||
$Output.GPOOrphans
|
||||
# Shows how to use exclusions (supported only in GPOBlockedInheritance)
|
||||
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type GPOBlockedInheritance -Online -Exclusions @(
|
||||
'OU=Test,OU=ITR02,DC=ad,DC=evotec,DC=xyz'
|
||||
)
|
||||
|
||||
<#
|
||||
# Shows how to use exclusions for GPOList (different way)
|
||||
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type GPOList -Online -Exclusions {
|
||||
Skip-GroupPolicy -Name 'de14_usr_std'
|
||||
Skip-GroupPolicy -Name 'ALL | Enable RDP' -DomaiName 'ad.evotec.xyz'
|
||||
}
|
||||
#>
|
||||
@@ -1,3 +1,3 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type NetLogonPermissions, GPOOrphans, GPOList, GPOConsistency, GPOOwners, GPODuplicates
|
||||
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type GPOConsistency, GPOList, GPODuplicates, GPOBroken, GPOOwners, NetLogonOwners, GPOPermissionsRead, GPOPermissionsAdministrative, GPOPermissionsUnknown, GPOPermissions
|
||||
@@ -5,7 +5,7 @@ $Types = @(
|
||||
@{ 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 = 'GPOBroken'; Path = "$PSScriptRoot\Reports\GPOBroken.html" }
|
||||
@{ Name = 'GPOPassword'; Path = "$PSScriptRoot\Reports\GPOPassword.html" }
|
||||
@{ Name = 'NetLogonPermissions'; Path = "$PSScriptRoot\Reports\NetLogonPermissions.html" }
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
$GPOS = Get-GPOZaurr -ExcludeGroupPolicies {
|
||||
Skip-GroupPolicy -Name 'de14_usr_std'
|
||||
Skip-GroupPolicy -Name 'de14_usr_std' -DomaiName 'ad.evotec.xyz'
|
||||
Skip-GroupPolicy -Name 'All | Trusted Websites' #-DomaiName 'ad.evotec.xyz'
|
||||
'{D39BF08A-87BF-4662-BFA0-E56240EBD5A2}'
|
||||
'COMPUTERS | Enable Sets'
|
||||
}
|
||||
$GPOS | Format-Table -AutoSize *
|
||||
|
||||
Invoke-GPOZaurr -Type GPOList -Exclusions {
|
||||
Skip-GroupPolicy -Name 'All | Trusted Websites' -DomaiName 'ad.evotec.xyz'
|
||||
'{D39BF08A-87BF-4662-BFA0-E56240EBD5A2}'
|
||||
'COMPUTERS | Enable Sets'
|
||||
}
|
||||
@@ -3,6 +3,6 @@
|
||||
# Optimize All
|
||||
Optimize-GPOZaurr -All -Verbose -IncludeDomains 'ad.evotec.pl' -LimitProcessing 1 {
|
||||
Skip-GroupPolicy -Name 'TEST | Empty GPO - AD.EVOTEC.PL CrossDomain GPO' -DomaiName 'ad.evotec.pl'
|
||||
}
|
||||
} -WhatIf
|
||||
# Optimize just one
|
||||
#Optimize-GPOZaurr -GPOName 'TEST | Empty GPO - AD.EVOTEC.PL CrossDomain GPO' -WhatIf -Verbose
|
||||
Optimize-GPOZaurr -GPOName 'TEST | Empty GPO - AD.EVOTEC.PL CrossDomain GPO' -WhatIf -Verbose
|
||||
@@ -0,0 +1,3 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Get-GPOZaurrPermissionAnalysis | Format-Table *
|
||||
@@ -0,0 +1,3 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Repair-GPOZaurrPermission -Verbose -WhatIf -Type Administrative -LimitProcessing 1
|
||||
@@ -0,0 +1,5 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
#Get-GPOZaurrBrokenLink -Verbose | Format-Table -AutoSize *
|
||||
|
||||
Get-GPOZaurrBrokenLink -Verbose -IncludeDomains ad.evotec.pl | Format-Table -AutoSize *
|
||||
@@ -0,0 +1,5 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Repair-GPOZaurrBrokenLink -Verbose -LimitProcessing 1 #-WhatIf
|
||||
|
||||
#Repair-GPOZaurrBrokenLink -Verbose -IncludeDomains ad.evotec.pl -LimitProcessing 30 #-WhatIf
|
||||
@@ -0,0 +1,10 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Remove-GPOZaurrLinkEmptyOU -Verbose -LimitProcessing 3 -WhatIf
|
||||
|
||||
$Exclude = @(
|
||||
"OU=Groups,OU=Production,DC=ad,DC=evotec,DC=pl"
|
||||
"OU=Test \, OU,OU=ITR02,DC=ad,DC=evotec,DC=xyz"
|
||||
)
|
||||
|
||||
Remove-GPOZaurrLinkEmptyOU -Verbose -LimitProcessing 3 -WhatIf -ExcludeOrganizationalUnit $Exclude
|
||||
@@ -0,0 +1,16 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Get-GPOZaurrOrganizationalUnit -Verbose -Option Unlink -Exclusions @(
|
||||
'OU=Groups,OU=Production,DC=ad,DC=evotec,DC=pl'
|
||||
) | Format-Table
|
||||
|
||||
Get-GPOZaurrOrganizationalUnit -Verbose -ExcludeOrganizationalUnit @(
|
||||
'*,OU=Production,DC=ad,DC=evotec,DC=pl'
|
||||
) | Format-Table
|
||||
|
||||
|
||||
Invoke-GPOZaurr -Type GPOOrganizationalUnit -Online -FilePath $PSScriptRoot\Reports\GPOZaurrOU.html -Exclusions @(
|
||||
'*OU=Production,DC=ad,DC=evotec,DC=pl'
|
||||
'*OU=Production,DC=ad,DC=evotec,DC=pl'
|
||||
'*OU=Production,DC=ad,DC=evotec,DC=pl'
|
||||
)
|
||||
+6
-6
@@ -4,11 +4,11 @@
|
||||
CmdletsToExport = @()
|
||||
CompanyName = 'Evotec'
|
||||
CompatiblePSEditions = @('Desktop')
|
||||
Copyright = '(c) 2011 - 2020 Przemyslaw Klys @ Evotec. All rights reserved.'
|
||||
Copyright = '(c) 2011 - 2021 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-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-GPOZaurrPermissionIssue', 'Get-GPOZaurrPermissionRoot', 'Get-GPOZaurrPermissionSummary', 'Get-GPOZaurrSysvolDFSR', 'Get-GPOZaurrWMI', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrContent', 'Invoke-GPOZaurrPermission', 'Invoke-GPOZaurrSupport', 'New-GPOZaurrWMI', 'Optimize-GPOZaurr', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrBroken', 'Remove-GPOZaurrDuplicateObject', 'Remove-GPOZaurrFolders', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrNetLogonOwner', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Set-GPOOwner', 'Set-GPOZaurrOwner', 'Set-GPOZaurrStatus', 'Skip-GroupPolicy')
|
||||
FunctionsToExport = @('Add-GPOPermission', 'Add-GPOZaurrPermission', 'Backup-GPOZaurr', 'Clear-GPOZaurrSysvolDFSR', 'ConvertFrom-CSExtension', 'Find-CSExtension', 'Get-GPOZaurr', 'Get-GPOZaurrAD', 'Get-GPOZaurrBackupInformation', 'Get-GPOZaurrBroken', 'Get-GPOZaurrBrokenLink', 'Get-GPOZaurrDictionary', 'Get-GPOZaurrDuplicateObject', 'Get-GPOZaurrFiles', 'Get-GPOZaurrFilesPolicyDefinition', 'Get-GPOZaurrFolders', 'Get-GPOZaurrInheritance', 'Get-GPOZaurrLegacyFiles', 'Get-GPOZaurrLink', 'Get-GPOZaurrLinkSummary', 'Get-GPOZaurrNetLogon', 'Get-GPOZaurrOrganizationalUnit', 'Get-GPOZaurrOwner', 'Get-GPOZaurrPassword', 'Get-GPOZaurrPermission', 'Get-GPOZaurrPermissionAnalysis', 'Get-GPOZaurrPermissionConsistency', 'Get-GPOZaurrPermissionIssue', 'Get-GPOZaurrPermissionRoot', 'Get-GPOZaurrPermissionSummary', 'Get-GPOZaurrSysvolDFSR', 'Get-GPOZaurrWMI', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrContent', 'Invoke-GPOZaurrPermission', 'Invoke-GPOZaurrSupport', 'New-GPOZaurrWMI', 'Optimize-GPOZaurr', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrBroken', 'Remove-GPOZaurrDuplicateObject', 'Remove-GPOZaurrFolders', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrLinkEmptyOU', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrBrokenLink', 'Repair-GPOZaurrNetLogonOwner', 'Repair-GPOZaurrPermission', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Set-GPOOwner', 'Set-GPOZaurrOwner', 'Set-GPOZaurrStatus', 'Skip-GroupPolicy')
|
||||
GUID = 'f7d4c9e4-0298-4f51-ad77-e8e3febebbde'
|
||||
ModuleVersion = '0.0.98'
|
||||
ModuleVersion = '0.0.136'
|
||||
PowerShellVersion = '5.1'
|
||||
PrivateData = @{
|
||||
PSData = @{
|
||||
@@ -18,15 +18,15 @@
|
||||
}
|
||||
}
|
||||
RequiredModules = @(@{
|
||||
ModuleVersion = '0.0.190'
|
||||
ModuleVersion = '0.0.210'
|
||||
ModuleName = 'PSSharedGoods'
|
||||
Guid = 'ee272aa8-baaa-4edf-9f45-b6d6f7d844fe'
|
||||
}, @{
|
||||
ModuleVersion = '0.0.103'
|
||||
ModuleVersion = '0.0.130'
|
||||
ModuleName = 'ADEssentials'
|
||||
Guid = '9fc9fd61-7f11-4f4b-a527-084086f1905f'
|
||||
}, @{
|
||||
ModuleVersion = '0.0.122'
|
||||
ModuleVersion = '0.0.158'
|
||||
ModuleName = 'PSWriteHTML'
|
||||
Guid = 'a7bdf640-f5cb-4acf-9de0-365b322d245c'
|
||||
}, 'CimCmdlets', 'Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Utility', 'Microsoft.PowerShell.Security')
|
||||
|
||||
+46
-6
@@ -2,13 +2,53 @@
|
||||
$Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue -Recurse )
|
||||
$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue -Recurse )
|
||||
|
||||
#Dot source the files
|
||||
Foreach ($import in @($Public + $Private)) {
|
||||
Try {
|
||||
. $import.fullname
|
||||
} Catch {
|
||||
Write-Error -Message "Failed to import function $($import.fullname): $_"
|
||||
$AssemblyFolders = Get-ChildItem -Path $PSScriptRoot\Lib -Directory -ErrorAction SilentlyContinue
|
||||
if ($AssemblyFolders.BaseName -contains 'Standard') {
|
||||
$Assembly = @( Get-ChildItem -Path $PSScriptRoot\Lib\Standard\*.dll -ErrorAction SilentlyContinue )
|
||||
} else {
|
||||
if ($PSEdition -eq 'Core') {
|
||||
$Assembly = @( Get-ChildItem -Path $PSScriptRoot\Lib\Core\*.dll -ErrorAction SilentlyContinue )
|
||||
} else {
|
||||
$Assembly = @( Get-ChildItem -Path $PSScriptRoot\Lib\Default\*.dll -ErrorAction SilentlyContinue )
|
||||
}
|
||||
}
|
||||
$FoundErrors = @(
|
||||
Foreach ($Import in @($Assembly)) {
|
||||
try {
|
||||
Add-Type -Path $Import.Fullname -ErrorAction Stop
|
||||
} catch [System.Reflection.ReflectionTypeLoadException] {
|
||||
Write-Warning "Processing $($Import.Name) Exception: $($_.Exception.Message)"
|
||||
$LoaderExceptions = $($_.Exception.LoaderExceptions) | Sort-Object -Unique
|
||||
foreach ($E in $LoaderExceptions) {
|
||||
Write-Warning "Processing $($Import.Name) LoaderExceptions: $($E.Message)"
|
||||
}
|
||||
$true
|
||||
#Write-Error -Message "StackTrace: $($_.Exception.StackTrace)"
|
||||
} catch {
|
||||
Write-Warning "Processing $($Import.Name) Exception: $($_.Exception.Message)"
|
||||
$LoaderExceptions = $($_.Exception.LoaderExceptions) | Sort-Object -Unique
|
||||
foreach ($E in $LoaderExceptions) {
|
||||
Write-Warning "Processing $($Import.Name) LoaderExceptions: $($E.Message)"
|
||||
}
|
||||
$true
|
||||
#Write-Error -Message "StackTrace: $($_.Exception.StackTrace)"
|
||||
}
|
||||
}
|
||||
#Dot source the files
|
||||
Foreach ($Import in @($Private + $Public)) {
|
||||
Try {
|
||||
. $Import.Fullname
|
||||
} Catch {
|
||||
Write-Error -Message "Failed to import functions from $($import.Fullname): $_"
|
||||
$true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if ($FoundErrors.Count -gt 0) {
|
||||
$ModuleName = (Get-ChildItem $PSScriptRoot\*.psd1).BaseName
|
||||
Write-Warning "Importing module $ModuleName failed. Fix errors before continuing."
|
||||
break
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function '*' -Alias '*'
|
||||
@@ -0,0 +1,101 @@
|
||||
function ConvertTo-XMLCertificates {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
[string[]] $Category,
|
||||
[switch] $SingleObject
|
||||
)
|
||||
$SkipNames = ('Name', 'LocalName', 'NamespaceURI', 'Prefix', 'NodeType', 'ParentNode', 'OwnerDocument', 'IsEmpty', 'Attributes', 'HasAttributes', 'SchemaInfo', 'InnerXml', 'InnerText', 'NextSibling', 'PreviousSibling', 'ChildNodes', 'FirstChild', 'LastChild', 'HasChildNodes', 'IsReadOnly', 'OuterXml', 'BaseURI', 'PreviousText')
|
||||
if ($SingleObject) {
|
||||
$CreateGPO = [ordered]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
Count = 0
|
||||
Settings = $null
|
||||
}
|
||||
[Array] $CreateGPO['Settings'] = foreach ($Setting in $GPO.DataSet) {
|
||||
$SettingName = $Setting.Name -split ":"
|
||||
$MySettings = [ordered] @{
|
||||
CreatedTime = $GPO.CreatedTime # : 06.06.2020 18:03:36
|
||||
ModifiedTime = $GPO.ModifiedTime # : 17.06.2020 16:08:10
|
||||
ReadTime = $GPO.ReadTime # : 13.08.2020 10:15:37
|
||||
SecurityDescriptor = $GPO.SecurityDescriptor # : SecurityDescriptor
|
||||
FilterDataAvailable = $GPO.FilterDataAvailable # : True
|
||||
}
|
||||
$Name = $SettingName[1]
|
||||
#$Name = Format-ToTitleCase -Text $Setting.Name -RemoveWhiteSpace -RemoveChar ',', '-', "'", '\(', '\)', ':'
|
||||
$MySettings['Name'] = $Name # $Setting.Name
|
||||
|
||||
ConvertTo-XMLNested -CreateGPO $MySettings -Setting $Setting -SkipNames $SkipNames #-Name $Name
|
||||
|
||||
if ($MySettings.Data) {
|
||||
$bytes = $MySettings.Data -replace '\r?\n' -split '(?<=\G.{2})' -ne '' -replace '^', '0x' -as [byte[]]
|
||||
$CertificateData = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($bytes)
|
||||
|
||||
$MySettings['NotBefore'] = $CertificateData.NotBefore
|
||||
$MySettings['NotAfter'] = $CertificateData.NotAfter
|
||||
$MySettings['HasPrivateKey'] = $CertificateData.HasPrivateKey
|
||||
$MySettings['Thumbprint'] = $CertificateData.Thumbprint
|
||||
$MySettings['SerialNumber'] = $CertificateData.SerialNumber
|
||||
$MySettings['Version'] = $CertificateData.Version
|
||||
$MySettings['Handle'] = $CertificateData.Handle
|
||||
$MySettings['SignatureAlgorithm'] = $CertificateData.SignatureAlgorithm.Value
|
||||
$MySettings['SignatureAlgorithmName'] = $CertificateData.SignatureAlgorithm.FriendlyName
|
||||
$MySettings['KeyUsages'] = $CertificateData.Extensions.KeyUsages
|
||||
$MySettings.Remove('Data')
|
||||
}
|
||||
|
||||
[PSCustomObject] $MySettings
|
||||
}
|
||||
|
||||
$CreateGPO['Count'] = $CreateGPO['Settings'].Count
|
||||
$CreateGPO['Linked'] = $GPO.Linked
|
||||
$CreateGPO['LinksCount'] = $GPO.LinksCount
|
||||
$CreateGPO['Links'] = $GPO.Links
|
||||
[PSCustomObject] $CreateGPO
|
||||
} else {
|
||||
foreach ($Setting in $GPO.DataSet) {
|
||||
$CreateGPO = [ordered]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
}
|
||||
$SettingName = $Setting.Name -split ":"
|
||||
$CreateGPO['CreatedTime'] = $GPO.CreatedTime # : 06.06.2020 18:03:36
|
||||
$CreateGPO['ModifiedTime'] = $GPO.ModifiedTime # : 17.06.2020 16:08:10
|
||||
$CreateGPO['ReadTime'] = $GPO.ReadTime # : 13.08.2020 10:15:37
|
||||
$CreateGPO['SecurityDescriptor'] = $GPO.SecurityDescriptor # : SecurityDescriptor
|
||||
$CreateGPO['FilterDataAvailable'] = $GPO.FilterDataAvailable # : True
|
||||
|
||||
$Name = $SettingName[1]
|
||||
$CreateGPO['Name'] = $Name # $Setting.Name
|
||||
|
||||
ConvertTo-XMLNested -CreateGPO $CreateGPO -Setting $Setting -SkipNames $SkipNames #-Name $Name
|
||||
|
||||
if ($CreateGPO.Data) {
|
||||
$bytes = $CreateGPO.Data -replace '\r?\n' -split '(?<=\G.{2})' -ne '' -replace '^', '0x' -as [byte[]]
|
||||
$CertificateData = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($bytes)
|
||||
|
||||
$CreateGPO['NotBefore'] = $CertificateData.NotBefore
|
||||
$CreateGPO['NotAfter'] = $CertificateData.NotAfter
|
||||
$CreateGPO['HasPrivateKey'] = $CertificateData.HasPrivateKey
|
||||
$CreateGPO['Thumbprint'] = $CertificateData.Thumbprint
|
||||
$CreateGPO['SerialNumber'] = $CertificateData.SerialNumber
|
||||
$CreateGPO['Version'] = $CertificateData.Version
|
||||
$CreateGPO['Handle'] = $CertificateData.Handle
|
||||
$CreateGPO['SignatureAlgorithm'] = $CertificateData.SignatureAlgorithm.Value
|
||||
$CreateGPO['SignatureAlgorithmName'] = $CertificateData.SignatureAlgorithm.FriendlyName
|
||||
$CreateGPO['KeyUsages'] = $CertificateData.Extensions.KeyUsages
|
||||
$CreateGPO.Remove('Data')
|
||||
}
|
||||
$CreateGPO['Filters'] = $Setting.Filters
|
||||
$CreateGPO['Linked'] = $GPO.Linked
|
||||
$CreateGPO['LinksCount'] = $GPO.LinksCount
|
||||
$CreateGPO['Links'] = $GPO.Links
|
||||
[PSCustomObject] $CreateGPO
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
function ConvertTo-XMLDriveMapSettings {
|
||||
function ConvertTo-XMLDriveMapSettings {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
function ConvertTo-XMLFolderRedirection {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
[switch] $SingleObject
|
||||
)
|
||||
if ($SingleObject) {
|
||||
$CreateGPO = [ordered]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
#GpoCategory = $GPOEntry.GpoCategory
|
||||
#GpoSettings = $GPOEntry.GpoSettings
|
||||
Count = 0
|
||||
Settings = $null
|
||||
}
|
||||
[Array] $CreateGPO['Settings'] = foreach ($Folder in $GPO.DataSet) {
|
||||
foreach ($Location in $Folder.Location) {
|
||||
[PSCustomObject] @{
|
||||
DestinationPath = $Location.DestinationPath
|
||||
SecuritySID = $Location.SecurityGroup.SID.'#text'
|
||||
SecurityName = $Location.SecurityGroup.Name.'#text'
|
||||
GrantExclusiveRights = if ($Folder.GrantExclusiveRights -eq 'true') { $true } else { $false }
|
||||
MoveContents = if ($Folder.MoveContents -eq 'true') { $true } else { $false }
|
||||
FollowParent = if ($Folder.FollowParent -eq 'true') { $true } else { $false }
|
||||
ApplyToDownLevel = if ($Folder.ApplyToDownLevel -eq 'true') { $true } else { $false }
|
||||
DoNotCare = if ($Folder.DoNotCare -eq 'true') { $true } else { $false }
|
||||
RedirectToLocal = if ($Folder.RedirectToLocal -eq 'true') { $true } else { $false }
|
||||
PolicyRemovalBehavior = $Folder.PolicyRemovalBehavior # : LeaveContents
|
||||
ConfigurationControl = if ($Folder.ConfigurationControl -eq 'GP') { 'Group Policy' } else { $Folder.ConfigurationControl } # : GP
|
||||
PrimaryComputerEvaluation = $Folder.PrimaryComputerEvaluation # : PrimaryComputerPolicyDisabled
|
||||
}
|
||||
}
|
||||
}
|
||||
$CreateGPO['Count'] = $CreateGPO['Settings'].Count
|
||||
$CreateGPO['Linked'] = $GPO.Linked
|
||||
$CreateGPO['LinksCount'] = $GPO.LinksCount
|
||||
$CreateGPO['Links'] = $GPO.Links
|
||||
[PSCustomObject] $CreateGPO
|
||||
} else {
|
||||
foreach ($Folder in $GPO.DataSet) {
|
||||
foreach ($Location in $Folder.Location) {
|
||||
$CreateGPO = [ordered]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
Id = $Folder.Id
|
||||
DestinationPath = $Location.DestinationPath
|
||||
SecuritySID = $Location.SecurityGroup.SID.'#text'
|
||||
SecurityName = $Location.SecurityGroup.Name.'#text'
|
||||
GrantExclusiveRights = if ($Folder.GrantExclusiveRights -eq 'true') { $true } else { $false }
|
||||
MoveContents = if ($Folder.MoveContents -eq 'true') { $true } else { $false }
|
||||
FollowParent = if ($Folder.FollowParent -eq 'true') { $true } else { $false }
|
||||
ApplyToDownLevel = if ($Folder.ApplyToDownLevel -eq 'true') { $true } else { $false }
|
||||
DoNotCare = if ($Folder.DoNotCare -eq 'true') { $true } else { $false }
|
||||
RedirectToLocal = if ($Folder.RedirectToLocal -eq 'true') { $true } else { $false }
|
||||
PolicyRemovalBehavior = $Folder.PolicyRemovalBehavior # : LeaveContents
|
||||
ConfigurationControl = if ($Folder.ConfigurationControl -eq 'GP') { 'Group Policy' } else { $Folder.ConfigurationControl } # : GP
|
||||
PrimaryComputerEvaluation = $Folder.PrimaryComputerEvaluation # : PrimaryComputerPolicyDisabled
|
||||
Linked = $GPO.Linked
|
||||
LinksCount = $GPO.LinksCount
|
||||
Links = $GPO.Links
|
||||
}
|
||||
[PSCustomObject] $CreateGPO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
function ConvertTo-XMLGenericPolicy {
|
||||
function ConvertTo-XMLGenericPolicy {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function ConvertTo-XMLGenericPublicKey {
|
||||
function ConvertTo-XMLGenericPublicKey {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function ConvertTo-XMLGenericSecuritySettings {
|
||||
function ConvertTo-XMLGenericSecuritySettings {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function ConvertTo-XMLLocalGroups {
|
||||
function ConvertTo-XMLLocalGroups {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function ConvertTo-XMLPrinter {
|
||||
function ConvertTo-XMLPrinter {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function ConvertTo-XMLPrinterInternal {
|
||||
function ConvertTo-XMLPrinterInternal {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function ConvertTo-XMLRegistryAutologonOnReport {
|
||||
function ConvertTo-XMLRegistryAutologonOnReport {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function ConvertTo-XMLTaskScheduler {
|
||||
function ConvertTo-XMLTaskScheduler {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
function ConvertTo-XMLWindowsFirewall {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
[switch] $SingleObject
|
||||
)
|
||||
if ($SingleObject) {
|
||||
$CreateGPO = [ordered]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
#GpoCategory = $GPOEntry.GpoCategory
|
||||
#GpoSettings = $GPOEntry.GpoSettings
|
||||
Count = 0
|
||||
Settings = $null
|
||||
}
|
||||
[Array] $CreateGPO['Settings'] = foreach ($Policy in $GPO.DataSet) {
|
||||
[PSCustomObject] @{
|
||||
Name = $Policy.LocalName
|
||||
Version = $Policy.PolicyVersion.Value
|
||||
}
|
||||
}
|
||||
$CreateGPO['Count'] = $CreateGPO['Settings'].Count
|
||||
$CreateGPO['Linked'] = $GPO.Linked
|
||||
$CreateGPO['LinksCount'] = $GPO.LinksCount
|
||||
$CreateGPO['Links'] = $GPO.Links
|
||||
[PSCustomObject] $CreateGPO
|
||||
} else {
|
||||
foreach ($Policy in $GPO.DataSet) {
|
||||
[PSCustomObject]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
Name = $Policy.LocalName
|
||||
Version = $Policy.PolicyVersion.Value
|
||||
Linked = $GPO.Linked
|
||||
LinksCount = $GPO.LinksCount
|
||||
Links = $GPO.Links
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
function ConvertTo-XMLWindowsFirewallConnectionSecurityAuthentiation {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
[switch] $SingleObject
|
||||
)
|
||||
if ($SingleObject) {
|
||||
$CreateGPO = [ordered]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
#GpoCategory = $GPOEntry.GpoCategory
|
||||
#GpoSettings = $GPOEntry.GpoSettings
|
||||
Count = 0
|
||||
Settings = $null
|
||||
}
|
||||
[Array] $CreateGPO['Settings'] = foreach ($Connection in $GPO.DataSet) {
|
||||
[PSCustomObject] @{
|
||||
Name = $Connection.LocalName
|
||||
Version = $Connection.Version
|
||||
ConnectionGUID = $Connection.GUID
|
||||
Method = $Connection.AuthenticationSuites.Method #: MachineCert
|
||||
CAName = $Connection.AuthenticationSuites.CAName #: DC = xyz, DC = evotec, DC = ad, CN = ad-ADCS-CA
|
||||
CertAccountMapping = if ($Connection.AuthenticationSuites.CertAccountMapping -eq 'true') { $true } elseif ($Connection.AuthenticationSuites.CertAccountMapping -eq 'false') { $false } else { $Connection.AuthenticationSuites.CertAccountMapping }
|
||||
ExcludeCAName = if ($Connection.AuthenticationSuites.ExcludeCAName -eq 'true') { $true } elseif ($Connection.AuthenticationSuites.ExcludeCAName -eq 'false') { $false } else { $Connection.AuthenticationSuites.ExcludeCAName }
|
||||
HealthCert = if ($Connection.AuthenticationSuites.HealthCert -eq 'true') { $true } elseif ($Connection.AuthenticationSuites.HealthCert -eq 'false') { $false } else { $Connection.AuthenticationSuites.HealthCert }
|
||||
}
|
||||
}
|
||||
$CreateGPO['Count'] = $CreateGPO['Settings'].Count
|
||||
$CreateGPO['Linked'] = $GPO.Linked
|
||||
$CreateGPO['LinksCount'] = $GPO.LinksCount
|
||||
$CreateGPO['Links'] = $GPO.Links
|
||||
[PSCustomObject] $CreateGPO
|
||||
} else {
|
||||
foreach ($Connection in $GPO.DataSet) {
|
||||
[PSCustomObject]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
Name = $Connection.LocalName
|
||||
Version = $Connection.Version
|
||||
ConnectionGUID = $Connection.GUID
|
||||
Method = $Connection.AuthenticationSuites.Method #: MachineCert
|
||||
CAName = $Connection.AuthenticationSuites.CAName #: DC = xyz, DC = evotec, DC = ad, CN = ad-ADCS-CA
|
||||
CertAccountMapping = if ($Connection.AuthenticationSuites.CertAccountMapping -eq 'true') { $true } elseif ($Connection.AuthenticationSuites.CertAccountMapping -eq 'false') { $false } else { $Connection.AuthenticationSuites.CertAccountMapping }
|
||||
ExcludeCAName = if ($Connection.AuthenticationSuites.ExcludeCAName -eq 'true') { $true } elseif ($Connection.AuthenticationSuites.ExcludeCAName -eq 'false') { $false } else { $Connection.AuthenticationSuites.ExcludeCAName }
|
||||
HealthCert = if ($Connection.AuthenticationSuites.HealthCert -eq 'true') { $true } elseif ($Connection.AuthenticationSuites.HealthCert -eq 'false') { $false } else { $Connection.AuthenticationSuites.HealthCert }
|
||||
Linked = $GPO.Linked
|
||||
LinksCount = $GPO.LinksCount
|
||||
Links = $GPO.Links
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
function ConvertTo-XMLWindowsFirewallProfile {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
[switch] $SingleObject
|
||||
)
|
||||
if ($SingleObject) {
|
||||
$CreateGPO = [ordered]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
#GpoCategory = $GPOEntry.GpoCategory
|
||||
#GpoSettings = $GPOEntry.GpoSettings
|
||||
Count = 0
|
||||
Settings = $null
|
||||
}
|
||||
[Array] $CreateGPO['Settings'] = foreach ($Profile in $GPO.DataSet) {
|
||||
[PSCustomObject] @{
|
||||
Profile = $Profile.LocalName
|
||||
EnableFirewall = if ($Profile.EnableFirewall.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
AllowLocalIPsecPolicyMerge = if ($Profile.AllowLocalIPsecPolicyMerge.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
AllowLocalPolicyMerge = if ($Profile.AllowLocalPolicyMerge.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
DefaultInboundAction = if ($Profile.DefaultInboundAction.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
DefaultOutboundAction = if ($Profile.DefaultOutboundAction.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
DisableNotifications = if ($Profile.DisableNotifications.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
DisableUnicastResponsesToMulticastBroadcast = if ($Profile.DisableUnicastResponsesToMulticastBroadcast.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
DoNotAllowExceptions = if ($Profile.DoNotAllowExceptions.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
LogFilePath = if ($Profile.LogFilePath.Value) { $Profile.LogFilePath.Value } else { 'Not configured' }
|
||||
LogDroppedPackets = if ($Profile.LogDroppedPackets.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
LogFileSize = if ($Profile.LogFileSize.Value) { $Profile.LogFileSize.Value } else { 'Not configured' }
|
||||
LogSuccessfulConnections = if ($Profile.LogSuccessfulConnections.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
}
|
||||
}
|
||||
$CreateGPO['Count'] = $CreateGPO['Settings'].Count
|
||||
$CreateGPO['Linked'] = $GPO.Linked
|
||||
$CreateGPO['LinksCount'] = $GPO.LinksCount
|
||||
$CreateGPO['Links'] = $GPO.Links
|
||||
[PSCustomObject] $CreateGPO
|
||||
} else {
|
||||
foreach ($Profile in $GPO.DataSet) {
|
||||
[PSCustomObject]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
Profile = $Profile.LocalName
|
||||
EnableFirewall = if ($Profile.EnableFirewall.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
AllowLocalIPsecPolicyMerge = if ($Profile.AllowLocalIPsecPolicyMerge.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
AllowLocalPolicyMerge = if ($Profile.AllowLocalPolicyMerge.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
DefaultInboundAction = if ($Profile.DefaultInboundAction.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
DefaultOutboundAction = if ($Profile.DefaultOutboundAction.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
DisableNotifications = if ($Profile.DisableNotifications.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
DisableUnicastResponsesToMulticastBroadcast = if ($Profile.DisableUnicastResponsesToMulticastBroadcast.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
DoNotAllowExceptions = if ($Profile.DoNotAllowExceptions.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
LogFilePath = if ($Profile.LogFilePath.Value) { $Profile.LogFilePath.Value } else { 'Not configured' }
|
||||
LogDroppedPackets = if ($Profile.LogDroppedPackets.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
LogFileSize = if ($Profile.LogFileSize.Value) { $Profile.LogFileSize.Value } else { 'Not configured' }
|
||||
LogSuccessfulConnections = if ($Profile.LogSuccessfulConnections.Value -eq 'true') { 'Yes' } elseif ($Profile.EnableFirewall.Value -eq 'false') { 'No' } else { 'Not configured' }
|
||||
Linked = $GPO.Linked
|
||||
LinksCount = $GPO.LinksCount
|
||||
Links = $GPO.Links
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
function ConvertTo-XMLWindowsFirewallRules {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
[switch] $SingleObject
|
||||
)
|
||||
if ($SingleObject) {
|
||||
$CreateGPO = [ordered]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
#GpoCategory = $GPOEntry.GpoCategory
|
||||
#GpoSettings = $GPOEntry.GpoSettings
|
||||
Count = 0
|
||||
Settings = $null
|
||||
}
|
||||
[Array] $CreateGPO['Settings'] = foreach ($Rule in $GPO.DataSet) {
|
||||
[PSCustomObject] @{
|
||||
Version = $Rule.Version
|
||||
Type = if ($Rule.Dir -eq 'In') { 'Inbound' } elseif ($Rule.Dir -eq 'Out') { 'Outbound' } else { $Rule.Dir }
|
||||
Name = $Rule.Name
|
||||
Action = $Rule.Action
|
||||
Enabled = if ($Rule.Active -eq 'true') { $true } else { $false }
|
||||
Profile = $Rule.Profile
|
||||
Svc = $Rule.Svc
|
||||
LocalAddressIPv4 = $Rule.LA4
|
||||
LocalAddressIPv6 = $Rule.LA6
|
||||
RemoteAddressIPV4 = $Rule.RA4
|
||||
RemoteAddressIPV6 = $Rule.RA6
|
||||
LocalPort = $Rule.LPort
|
||||
RemotePort = $Rule.RPort
|
||||
Description = $Rule.Desc
|
||||
EmbedCtxt = $Rule.EmbedCtxt
|
||||
Edge = $Rule.Edge
|
||||
IFType = $Rule.IFType
|
||||
Security = $Rule.Security
|
||||
App = $Rule.App
|
||||
Protocol = $Rule.Protocol
|
||||
RMAuth = $Rule.RMAuth
|
||||
RUAuth = $Rule.RUAuth
|
||||
ICMP4 = $Rule.ICMP4
|
||||
LocalName = $Rule.LocalName
|
||||
|
||||
}
|
||||
}
|
||||
$CreateGPO['Count'] = $CreateGPO['Settings'].Count
|
||||
$CreateGPO['Linked'] = $GPO.Linked
|
||||
$CreateGPO['LinksCount'] = $GPO.LinksCount
|
||||
$CreateGPO['Links'] = $GPO.Links
|
||||
[PSCustomObject] $CreateGPO
|
||||
} else {
|
||||
foreach ($Rule in $GPO.DataSet) {
|
||||
[PSCustomObject]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
Version = $Rule.Version
|
||||
Type = if ($Rule.Dir -eq 'In') { 'Inbound' } elseif ($Rule.Dir -eq 'Out') { 'Outbound' } else { $Rule.Dir }
|
||||
Name = $Rule.Name
|
||||
Action = $Rule.Action
|
||||
Enabled = if ($Rule.Active -eq 'true') { $true } else { $false }
|
||||
Profile = $Rule.Profile
|
||||
Svc = $Rule.Svc
|
||||
LocalAddressIPv4 = $Rule.LA4
|
||||
LocalAddressIPv6 = $Rule.LA6
|
||||
RemoteAddressIPV4 = $Rule.RA4
|
||||
RemoteAddressIPV6 = $Rule.RA6
|
||||
LocalPort = $Rule.LPort
|
||||
RemotePort = $Rule.RPort
|
||||
Description = $Rule.Desc
|
||||
EmbedCtxt = $Rule.EmbedCtxt
|
||||
Edge = $Rule.Edge
|
||||
IFType = $Rule.IFType
|
||||
Security = $Rule.Security
|
||||
App = $Rule.App
|
||||
Protocol = $Rule.Protocol
|
||||
RMAuth = $Rule.RMAuth
|
||||
RUAuth = $Rule.RUAuth
|
||||
ICMP4 = $Rule.ICMP4
|
||||
LocalName = $Rule.LocalName
|
||||
Linked = $GPO.Linked
|
||||
LinksCount = $GPO.LinksCount
|
||||
Links = $GPO.Links
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
<#
|
||||
Version : 2.30
|
||||
Action : Allow
|
||||
Name : @%SystemRoot%\system32\firewallapi.dll,-37303
|
||||
Dir : In
|
||||
App : %SystemRoot%\system32\svchost.exe
|
||||
Svc : dnscache
|
||||
Profile : Public
|
||||
RA4 : LocalSubnet
|
||||
RA6 : LocalSubnet
|
||||
LPort : 5353
|
||||
Protocol : 17
|
||||
Desc : @%SystemRoot%\system32\firewallapi.dll,-37304
|
||||
Active : true
|
||||
EmbedCtxt : @%SystemRoot%\system32\firewallapi.dll,-37302
|
||||
|
||||
|
||||
Version : 2.30
|
||||
Action : Allow
|
||||
Name : TEST APP
|
||||
Dir : In
|
||||
App : C:\Test\exe.exe
|
||||
Active : true
|
||||
|
||||
Version : 2.30
|
||||
Action : Block
|
||||
Name : Blo
|
||||
Dir : Out
|
||||
App : dfdff
|
||||
Active : true
|
||||
|
||||
Version : 2.30
|
||||
Action : Block
|
||||
Name : @FirewallAPI.dll,-36012
|
||||
Dir : Out
|
||||
App : %SystemRoot%\system32\svchost.exe
|
||||
Svc : Qwave
|
||||
Profile : {Private, Public}
|
||||
RPort : 2177
|
||||
Protocol : 17
|
||||
Desc : @FirewallAPI.dll,-36013
|
||||
Active : true
|
||||
EmbedCtxt : @FirewallAPI.dll,-36001
|
||||
#>
|
||||
@@ -0,0 +1,76 @@
|
||||
function ConvertTo-XMLWindowsFirewallSecurityRules {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
[switch] $SingleObject
|
||||
)
|
||||
if ($SingleObject) {
|
||||
$CreateGPO = [ordered]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
#GpoCategory = $GPOEntry.GpoCategory
|
||||
#GpoSettings = $GPOEntry.GpoSettings
|
||||
Count = 0
|
||||
Settings = $null
|
||||
}
|
||||
[Array] $CreateGPO['Settings'] = foreach ($Rule in $GPO.DataSet) {
|
||||
[PSCustomObject] @{
|
||||
Version = $Rule.Version
|
||||
Name = $Rule.Name
|
||||
Action = $Rule.Action
|
||||
Enabled = if ($Rule.Active -eq 'true') { $true } else { $false }
|
||||
Auth1Set = $Rule.Auth1Set
|
||||
Auth2Set = $Rule.Auth2Set
|
||||
Crypto2Set = $Rule.Crypto2Set
|
||||
Description = $Rule.Desc
|
||||
}
|
||||
}
|
||||
$CreateGPO['Count'] = $CreateGPO['Settings'].Count
|
||||
$CreateGPO['Linked'] = $GPO.Linked
|
||||
$CreateGPO['LinksCount'] = $GPO.LinksCount
|
||||
$CreateGPO['Links'] = $GPO.Links
|
||||
[PSCustomObject] $CreateGPO
|
||||
} else {
|
||||
foreach ($Rule in $GPO.DataSet) {
|
||||
[PSCustomObject]@{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
Version = $Rule.Version
|
||||
Name = $Rule.Name
|
||||
Action = $Rule.Action
|
||||
Enabled = if ($Rule.Active -eq 'true') { $true } else { $false }
|
||||
Auth1Set = $Rule.Auth1Set
|
||||
Auth2Set = $Rule.Auth2Set
|
||||
Crypto2Set = $Rule.Crypto2Set
|
||||
Description = $Rule.Desc
|
||||
Linked = $GPO.Linked
|
||||
LinksCount = $GPO.LinksCount
|
||||
Links = $GPO.Links
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
Version : 2.30
|
||||
Action : Boundary
|
||||
Name : TeST Aut
|
||||
Auth1Set : {E5A5D32A-4BCE-4e4d-B07F-4AB1BA7E5FE3}
|
||||
Auth2Set : {E5A5D32A-4BCE-4e4d-B07F-4AB1BA7E5FE4}
|
||||
Crypto2Set : {E5A5D32A-4BCE-4e4d-B07F-4AB1BA7E5FE2}
|
||||
Desc :
|
||||
Active : true
|
||||
|
||||
Version : 2.30
|
||||
Action : Boundary
|
||||
Name : CA TEST
|
||||
Auth1Set : {0E3A2DDC-F31B-42B5-BEAC-890752F9C0BB}
|
||||
Auth2Set : EmptySet
|
||||
Crypto2Set : {E5A5D32A-4BCE-4e4d-B07F-4AB1BA7E5FE2}
|
||||
Desc :
|
||||
Active : true
|
||||
#>
|
||||
@@ -1,4 +1,4 @@
|
||||
function Get-GPOCategories {
|
||||
function Get-GPOCategories {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO,
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
function Get-GPOPrivInheritance {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
|
||||
[System.Collections.IDictionary] $CacheReturnedGPOs,
|
||||
[System.Collections.IDictionary] $ForestInformation,
|
||||
[string] $Domain,
|
||||
[switch] $SkipDomainRoot,
|
||||
[switch] $SkipDomainControllers
|
||||
)
|
||||
foreach ($Object in $ADObject) {
|
||||
if ($SkipDomainRoot) {
|
||||
if ($Object.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']) {
|
||||
# other skips Domain Root
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ($SkipDomainControllers) {
|
||||
if ($Object.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']) {
|
||||
# other skips Domain Controllers
|
||||
continue
|
||||
}
|
||||
}
|
||||
$Inheritance = Get-GPInheritance -Target $Object.DistinguishedName
|
||||
foreach ($Link in $Inheritance.GpoLinks) {
|
||||
[PSCustomObject] @{
|
||||
DisplayName = $Link.DisplayName
|
||||
DomainName = $Domain
|
||||
GUID = $Link.GPOID
|
||||
Enabled = $Link.Enabled
|
||||
Enforced = $Link.Enforced
|
||||
Order = $Link.Order
|
||||
Target = $Object.DistinguishedName
|
||||
TargetCanonical = $Object.CanonicalName
|
||||
TargetObjectClass = $Object.objectClass
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
function Get-GPOPrivInheritanceLoop {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
|
||||
[System.Collections.IDictionary] $CacheReturnedGPOs,
|
||||
[System.Collections.IDictionary] $ForestInformation,
|
||||
[validateset('Root', 'DomainControllers', 'OrganizationalUnit')][string[]] $Linked,
|
||||
[string] $SearchBase,
|
||||
[Microsoft.ActiveDirectory.Management.ADSearchScope] $SearchScope,
|
||||
[string] $Filter
|
||||
)
|
||||
if (-not $ADObject) {
|
||||
if ($Linked) {
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
$Splat = @{
|
||||
#Filter = $Filter
|
||||
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
|
||||
# Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
|
||||
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
|
||||
}
|
||||
if ($Linked -contains 'DomainControllers') {
|
||||
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']
|
||||
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
Get-GPOPrivInheritance -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation
|
||||
}
|
||||
if ($Linked -contains 'Root') {
|
||||
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
|
||||
$Splat['Filter'] = "objectClass -eq 'domainDNS'"
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
Get-GPOPrivInheritance -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation
|
||||
}
|
||||
if ($Linked -contains 'Site') {
|
||||
# Sites are defined only in primary domain
|
||||
# Sites are not supported by Get-GPInheritance
|
||||
}
|
||||
if ($Linked -contains 'OrganizationalUnit') {
|
||||
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
|
||||
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
Get-GPOPrivInheritance -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -SkipDomainRoot -SkipDomainControllers
|
||||
}
|
||||
}
|
||||
} elseif ($Filter) {
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
$Splat = @{
|
||||
Filter = $Filter
|
||||
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
|
||||
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
|
||||
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey('SearchBase')) {
|
||||
$DomainDistinguishedName = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
|
||||
$SearchBaseDC = ConvertFrom-DistinguishedName -DistinguishedName $SearchBase -ToDC
|
||||
if ($SearchBaseDC -ne $DomainDistinguishedName) {
|
||||
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
|
||||
continue
|
||||
}
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey('SearchScope')) {
|
||||
$Splat['SearchScope'] = $SearchScope
|
||||
}
|
||||
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
Get-GPOPrivInheritance -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Get-GPOPrivInheritance -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObject -Domain '' -ForestInformation $ForestInformation
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
function Get-GPOPrivLink {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
|
||||
[System.Collections.IDictionary] $CacheReturnedGPOs,
|
||||
[System.Collections.IDictionary] $ForestInformation,
|
||||
[string] $Domain,
|
||||
[switch] $SkipDomainRoot,
|
||||
[switch] $SkipDomainControllers,
|
||||
[switch] $AsHashTable,
|
||||
[switch] $SkipDuplicates
|
||||
)
|
||||
foreach ($Object in $ADObject) {
|
||||
if ($SkipDomainRoot) {
|
||||
if ($Object.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']) {
|
||||
# other skips Domain Root
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ($SkipDomainControllers) {
|
||||
if ($Object.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']) {
|
||||
# other skips Domain Controllers
|
||||
continue
|
||||
}
|
||||
}
|
||||
$OutputGPOs = Get-PrivGPOZaurrLink -Object $Object -Limited:$Limited.IsPresent -GPOCache $GPOCache
|
||||
foreach ($OutputGPO in $OutputGPOs) {
|
||||
if (-not $SkipDuplicates) {
|
||||
$OutputGPO
|
||||
} else {
|
||||
$UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid)
|
||||
if (-not $CacheReturnedGPOs[$UniqueGuid]) {
|
||||
$CacheReturnedGPOs[$UniqueGuid] = $OutputGPO
|
||||
$OutputGPO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
function Get-GPOZaurrLinkInheritance {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Short description
|
||||
|
||||
.DESCRIPTION
|
||||
Long description
|
||||
|
||||
.PARAMETER ADObject
|
||||
Parameter description
|
||||
|
||||
.PARAMETER Filter
|
||||
Parameter description
|
||||
|
||||
.PARAMETER SearchBase
|
||||
Parameter description
|
||||
|
||||
.PARAMETER SearchScope
|
||||
Parameter description
|
||||
|
||||
.PARAMETER Linked
|
||||
Parameter description
|
||||
|
||||
.PARAMETER Limited
|
||||
Parameter description
|
||||
|
||||
.PARAMETER SkipDuplicates
|
||||
Parameter description
|
||||
|
||||
.PARAMETER GPOCache
|
||||
Parameter description
|
||||
|
||||
.PARAMETER Forest
|
||||
Parameter description
|
||||
|
||||
.PARAMETER ExcludeDomains
|
||||
Parameter description
|
||||
|
||||
.PARAMETER IncludeDomains
|
||||
Parameter description
|
||||
|
||||
.PARAMETER ExtendedForestInformation
|
||||
Parameter description
|
||||
|
||||
.PARAMETER AsHashTable
|
||||
Parameter description
|
||||
|
||||
.PARAMETER Summary
|
||||
Parameter description
|
||||
|
||||
.EXAMPLE
|
||||
$Output = Get-GPOZaurrLinkInheritance -Summary
|
||||
$Output | Format-Table
|
||||
|
||||
$Output[5]
|
||||
|
||||
$Output[5].Links | Format-Table
|
||||
$Output[5].LinksObjects | Format-Table
|
||||
|
||||
.NOTES
|
||||
This is based on Get-GPInheritance which isn't ideal and doesn't support sites. Get-GPOZaurrLink is better. Leaving in case I need it later on for private use only.
|
||||
#>
|
||||
[cmdletbinding(DefaultParameterSetName = 'All')]
|
||||
param(
|
||||
[parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
|
||||
# weirdly enough site doesn't really work this way unless you give it 'CN=Configuration,DC=ad,DC=evotec,DC=xyz' as SearchBase
|
||||
[parameter(ParameterSetName = 'Filter')][string] $Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')",
|
||||
[parameter(ParameterSetName = 'Filter')][string] $SearchBase,
|
||||
[parameter(ParameterSetName = 'Filter')][Microsoft.ActiveDirectory.Management.ADSearchScope] $SearchScope,
|
||||
|
||||
[parameter(ParameterSetName = 'Linked', Mandatory)][validateset('Root', 'DomainControllers', 'OrganizationalUnit')][string[]] $Linked,
|
||||
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[switch] $Limited,
|
||||
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[switch] $SkipDuplicates,
|
||||
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[System.Collections.IDictionary] $GPOCache,
|
||||
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[alias('ForestName')][string] $Forest,
|
||||
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[string[]] $ExcludeDomains,
|
||||
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
|
||||
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation,
|
||||
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[switch] $AsHashTable,
|
||||
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[switch] $Summary
|
||||
)
|
||||
Begin {
|
||||
$CacheReturnedGPOs = [ordered] @{}
|
||||
$ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
if (-not $GPOCache -and -not $Limited) {
|
||||
$GPOCache = @{ }
|
||||
# While initially we used $ForestInformation.Domains but the thing is GPOs can be linked to other domains so we need to get them all so we can use cache of it later on even if we're processing just one domain
|
||||
# That's why we use $ForestInformation.Forest.Domains instead
|
||||
foreach ($Domain in $ForestInformation.Forest.Domains) {
|
||||
$QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
|
||||
Get-GPO -All -DomainName $Domain -Server $QueryServer | ForEach-Object {
|
||||
$GPOCache["$Domain$($_.ID.Guid)"] = $_
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Process {
|
||||
if (-not $Filter -and -not $Linked) {
|
||||
# We choose ALL, except SITE which is not supported gor Get-GPInheritance
|
||||
# that's why it's better to use Get-GPOZaurrLink
|
||||
#$Linked = 'Root', 'DomainControllers', 'Site', 'OrganizationalUnit'
|
||||
}
|
||||
$getGPOPrivInheritanceLoopSplat = @{
|
||||
Linked = $Linked
|
||||
ForestInformation = $ForestInformation
|
||||
CacheReturnedGPOs = $CacheReturnedGPOs
|
||||
SearchScope = $SearchScope
|
||||
SearchBase = $SearchBase
|
||||
ADObject = $ADObject
|
||||
Filter = $Filter
|
||||
}
|
||||
Remove-EmptyValue -Hashtable $getGPOPrivInheritanceLoopSplat -Recursive
|
||||
|
||||
# we need to use nested functions to support pipeline output and as hashtable and reporting that returns single value
|
||||
if ($AsHashTable -or $Summary) {
|
||||
$HashTable = [ordered] @{}
|
||||
$SummaryHashtable = [ordered] @{}
|
||||
$Links = Get-GPOPrivInheritanceLoop @getGPOPrivInheritanceLoopSplat
|
||||
foreach ($Link in $Links) {
|
||||
$Key = -join ($Link.DomainName, $Link.GUID)
|
||||
if (-not $HashTable[$Key]) {
|
||||
$HashTable[$Key] = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
}
|
||||
$HashTable[$Key].Add($Link)
|
||||
}
|
||||
foreach ($Key in $HashTable.Keys) {
|
||||
[Array] $Link = $HashTable[$Key]
|
||||
$EnabledLinks = $Link.Enabled.Where( { $_ -eq $true }, 'split')
|
||||
if ($EnabledLinks[0].Count -gt 0) {
|
||||
$IsLinked = $true
|
||||
} else {
|
||||
$IsLinked = $false
|
||||
}
|
||||
$SummaryLink = [PSCustomObject] @{
|
||||
DisplayName = $Link[0].DisplayName
|
||||
DomainName = $Link[0].DomainName
|
||||
GUID = $Link[0].GUID
|
||||
Linked = $IsLinked
|
||||
LinksCount = $Link.Count
|
||||
LinksEnabledCount = $EnabledLinks[0].Count
|
||||
LinksDisabledCount = $EnabledLinks[1].Count
|
||||
Links = $Link.Target
|
||||
LinksObjects = $Link
|
||||
}
|
||||
$SummaryHashtable[$Key] = $SummaryLink
|
||||
}
|
||||
if ($AsHashTable -and $Summary) {
|
||||
$SummaryHashtable
|
||||
} elseif ($AsHashTable) {
|
||||
$HashTable
|
||||
} elseif ($Summary) {
|
||||
$SummaryHashtable.Values
|
||||
}
|
||||
} else {
|
||||
Get-GPOPrivInheritanceLoop @getGPOPrivInheritanceLoopSplat
|
||||
}
|
||||
}
|
||||
End {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
function Get-GPOZaurrLinkLoop {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
|
||||
[System.Collections.IDictionary] $CacheReturnedGPOs,
|
||||
[System.Collections.IDictionary] $ForestInformation,
|
||||
[validateset('All', 'Root', 'DomainControllers', 'Site', 'OrganizationalUnit')][string[]] $Linked,
|
||||
[string] $SearchBase,
|
||||
[Microsoft.ActiveDirectory.Management.ADSearchScope] $SearchScope,
|
||||
[string] $Filter,
|
||||
[switch] $SkipDuplicates,
|
||||
[string[]] $Site
|
||||
)
|
||||
if (-not $ADObject) {
|
||||
if ($Site) {
|
||||
foreach ($S in $Site) {
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for site $Site"
|
||||
# Sites are defined only in primary domain
|
||||
if ($ForestInformation['DomainsExtended'][$Domain]['DNSRoot'] -eq $ForestInformation['DomainsExtended'][$Domain]['Forest']) {
|
||||
$Splat = @{
|
||||
#Filter = $Filter
|
||||
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
|
||||
# Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
|
||||
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
|
||||
}
|
||||
$Splat['Filter'] = "(objectClass -eq 'site') -and (name -eq '$S')"
|
||||
$Splat['SearchBase'] = -join ("CN=Configuration,", $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName'])
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
if ($ADObjectGPO) {
|
||||
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($SearchBase -or $SearchScope -or $Filter) {
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
if (-not $Filter) {
|
||||
$Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
|
||||
}
|
||||
$Splat = @{
|
||||
Filter = $Filter
|
||||
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
|
||||
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey('SearchBase')) {
|
||||
$DomainDistinguishedName = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
|
||||
$SearchBaseDC = ConvertFrom-DistinguishedName -DistinguishedName $SearchBase -ToDC
|
||||
if ($SearchBaseDC -ne $DomainDistinguishedName) {
|
||||
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
|
||||
continue
|
||||
}
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey('SearchScope')) {
|
||||
$Splat['SearchScope'] = $SearchScope
|
||||
}
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
if ($ADObjectGPO) {
|
||||
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
|
||||
}
|
||||
}
|
||||
} elseif (-not $Filter) {
|
||||
# if not linked, we force it to All
|
||||
if (-not $Linked) {
|
||||
$Linked = 'All'
|
||||
}
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for domain $Domain"
|
||||
$Splat = @{
|
||||
#Filter = $Filter
|
||||
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
|
||||
# Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
|
||||
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
|
||||
}
|
||||
if ($Linked -contains 'Root' -or $Linked -contains 'All') {
|
||||
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for domain $Domain at ROOT level"
|
||||
$Splat['Filter'] = "objectClass -eq 'domainDNS'"
|
||||
$Splat['SearchBase'] = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
if ($ADObjectGPO) {
|
||||
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
|
||||
}
|
||||
}
|
||||
if ($Linked -contains 'Site' -or $Linked -contains 'All') {
|
||||
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for domain $Domain at SITE level"
|
||||
# Sites are defined only in primary domain
|
||||
if ($ForestInformation['DomainsExtended'][$Domain]['DNSRoot'] -eq $ForestInformation['DomainsExtended'][$Domain]['Forest']) {
|
||||
$Splat['Filter'] = "(objectClass -eq 'site')"
|
||||
$Splat['SearchBase'] = -join ("CN=Configuration,", $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName'])
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
if ($ADObjectGPO) {
|
||||
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Linked -contains 'DomainControllers' -or $Linked -contains 'All') {
|
||||
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for domain $Domain at DC level"
|
||||
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
|
||||
$Splat['SearchBase'] = $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
if ($ADObjectGPO) {
|
||||
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
|
||||
}
|
||||
}
|
||||
if ($Linked -contains 'OrganizationalUnit' -or $Linked -contains 'All') {
|
||||
Write-Verbose "Get-GPOZaurrLink - Getting GPO links for domain $Domain at OU level"
|
||||
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
|
||||
$Splat['SearchBase'] = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
if ($ADObjectGPO) {
|
||||
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -SkipDomainRoot -SkipDomainControllers -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
<#
|
||||
elseif ($Filter) {
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
$Splat = @{
|
||||
Filter = $Filter
|
||||
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
|
||||
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey('SearchBase')) {
|
||||
$DomainDistinguishedName = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
|
||||
$SearchBaseDC = ConvertFrom-DistinguishedName -DistinguishedName $SearchBase -ToDC
|
||||
if ($SearchBaseDC -ne $DomainDistinguishedName) {
|
||||
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
|
||||
continue
|
||||
}
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey('SearchScope')) {
|
||||
$Splat['SearchScope'] = $SearchScope
|
||||
}
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
if ($ADObjectGPO) {
|
||||
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObjectGPO -Domain $Domain -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
|
||||
}
|
||||
}
|
||||
}
|
||||
#>
|
||||
} else {
|
||||
Get-GPOPrivLink -CacheReturnedGPOs $CacheReturnedGPOs -ADObject $ADObject -Domain '' -ForestInformation $ForestInformation -AsHashTable:$AsHashTable -SkipDuplicates:$SkipDuplicates
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,10 @@
|
||||
if (-not $ADAdministrativeGroups) {
|
||||
$ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
}
|
||||
$AdministrativeExists = @{
|
||||
$AdministrativeExists = [ordered] @{
|
||||
DisplayName = $GPOPermissions[0].DisplayName
|
||||
DomainName = $GPOPermissions[0].DomainName
|
||||
GUID = $GPOPermissions[0].GUID
|
||||
Skip = $false
|
||||
DomainAdmins = $false
|
||||
EnterpriseAdmins = $false
|
||||
@@ -55,5 +58,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
$AdministrativeExists
|
||||
[PSCustomObject] $AdministrativeExists
|
||||
}
|
||||
@@ -6,69 +6,71 @@
|
||||
[System.Collections.IDictionary] $GPOCache
|
||||
)
|
||||
if ($Object.GpLink -and $Object.GpLink.Trim() -ne '') {
|
||||
#$Object.GpLink -split { $_ -eq '[' -or $_ -eq ']' } -replace ';0' -replace 'LDAP://'
|
||||
$Object.GpLink -split '\[LDAP://' -split ';' | ForEach-Object -Process {
|
||||
#Write-Verbose $_
|
||||
if ($_.Length -gt 10) {
|
||||
$DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDomainCN
|
||||
$Output = [ordered] @{
|
||||
DistinguishedName = $Object.DistinguishedName
|
||||
CanonicalName = if ($Object.CanonicalName) { $Object.CanonicalName.TrimEnd('/') } else { $Object.CanonicalName }
|
||||
Guid = [Regex]::Match( $_, '(?={)(.*)(?<=})').Value -replace '{' -replace '}'
|
||||
}
|
||||
$Search = -join ($DomainCN, $Output['Guid'])
|
||||
if ($GPOCache -and -not $Limited) {
|
||||
if ($GPOCache[$Search]) {
|
||||
$Output['DisplayName'] = $GPOCache[$Search].DisplayName
|
||||
$Output['DomainName'] = $GPOCache[$Search].DomainName
|
||||
$Output['Owner'] = $GPOCache[$Search].Owner
|
||||
$Output['GpoStatus'] = $GPOCache[$Search].GpoStatus
|
||||
$Output['Description'] = $GPOCache[$Search].Description
|
||||
$Output['CreationTime'] = $GPOCache[$Search].CreationTime
|
||||
$Output['ModificationTime'] = $GPOCache[$Search].ModificationTime
|
||||
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC
|
||||
$Output['GPODistinguishedName'] = $_
|
||||
[PSCustomObject] $Output
|
||||
} else {
|
||||
Write-Warning "Get-PrivGPOZaurrLink - Couldn't find link $Search in a GPO Cache. Lack of permissions for given GPO? Are you running as admin? Skipping."
|
||||
}
|
||||
} else {
|
||||
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC
|
||||
$Output['GPODistinguishedName'] = $_
|
||||
[PSCustomObject] $Output
|
||||
}
|
||||
}
|
||||
}
|
||||
$ObjectsToProcess = $Object.GpLink -split '\]\['
|
||||
} elseif ($Object.LinkedGroupPolicyObjects -and $Object.LinkedGroupPolicyObjects.Trim() -ne '') {
|
||||
$Object.LinkedGroupPolicyObjects -split '\[LDAP://' -split ';' | ForEach-Object -Process {
|
||||
if ($_.Length -gt 10) {
|
||||
$DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDomainCN
|
||||
$Output = [ordered] @{
|
||||
DistinguishedName = $Object.DistinguishedName
|
||||
CanonicalName = if ($Object.CanonicalName) { $Object.CanonicalName.TrimEnd('/') } else { $Object.CanonicalName }
|
||||
Guid = [Regex]::Match( $_, '(?={)(.*)(?<=})').Value -replace '{' -replace '}'
|
||||
}
|
||||
$Search = -join ($DomainCN, $Output['Guid'])
|
||||
if ($GPOCache -and -not $Limited) {
|
||||
if ($GPOCache[$Search]) {
|
||||
$Output['Name'] = $GPOCache[$Search].DisplayName
|
||||
$Output['DomainName'] = $GPOCache[$Search].DomainName
|
||||
$Output['Owner'] = $GPOCache[$Search].Owner
|
||||
$Output['GpoStatus'] = $GPOCache[$Search].GpoStatus
|
||||
$Output['Description'] = $GPOCache[$Search].Description
|
||||
$Output['CreationTime'] = $GPOCache[$Search].CreationTime
|
||||
$Output['ModificationTime'] = $GPOCache[$Search].ModificationTime
|
||||
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC
|
||||
$Output['GPODistinguishedName'] = $_
|
||||
[PSCustomObject] $Output
|
||||
} else {
|
||||
Write-Warning "Get-PrivGPOZaurrLink - Couldn't find link $Search in a GPO Cache. Lack of permissions for given GPO? Are you running as admin? Skipping."
|
||||
}
|
||||
$ObjectsToProcess = $Object.LinkedGroupPolicyObjects -split '\]\['
|
||||
} else {
|
||||
$ObjectsToProcess = $null
|
||||
}
|
||||
$ObjectsToProcess | ForEach-Object -Process {
|
||||
$Link = $_ -replace 'LDAP://' -replace '\]' -replace '\['
|
||||
if ($Link.Length -gt 10) {
|
||||
$SplitGPLink = $Link -split ';'
|
||||
$DN = $SplitGPLink[0]
|
||||
$Option = $SplitGPLink[1]
|
||||
if ($Option -eq '0') {
|
||||
$Enforced = $false
|
||||
$Enabled = $true
|
||||
} elseif ($Option -eq '1') {
|
||||
$Enabled = $false
|
||||
$Enforced = $false
|
||||
} elseif ($Option -eq '2') {
|
||||
$Enabled = $true
|
||||
$Enforced = $true
|
||||
} elseif ($Option -eq '3') {
|
||||
$Enabled = $false
|
||||
$Enforced = $true
|
||||
} else {
|
||||
if ($Object.GpLink) {
|
||||
Write-Warning "Get-PrivGPOZaurrLink - This should't happen. Please investigate - Option: $Option"
|
||||
} else {
|
||||
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_ -ToDC
|
||||
$Output['GPODistinguishedName'] = $_
|
||||
[PSCustomObject] $Output
|
||||
Write-Warning "Get-PrivGPOZaurrLink - Property GPLink is required to be able to tell if Enabled/Enforced is added. Skipping those settings."
|
||||
}
|
||||
$Enabled = $null
|
||||
$Enforced = $null
|
||||
}
|
||||
$DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $DN -ToDomainCN
|
||||
$Output = [ordered] @{
|
||||
DistinguishedName = $Object.DistinguishedName
|
||||
#Domain = ConvertFrom-DistinguishedName -DistinguishedName $Object.DistinguishedName -ToDomainCN
|
||||
CanonicalName = if ($Object.CanonicalName) { $Object.CanonicalName.TrimEnd('/') } else { $Object.CanonicalName }
|
||||
Guid = [Regex]::Match($DN, '(?={)(.*)(?<=})').Value -replace '{' -replace '}'
|
||||
Enforced = $Enforced
|
||||
Enabled = $Enabled
|
||||
ObjectClass = $Object.ObjectClass
|
||||
}
|
||||
$Search = -join ($DomainCN, $Output['Guid'])
|
||||
if ($GPOCache -and -not $Limited) {
|
||||
if ($GPOCache[$Search]) {
|
||||
$Output['DisplayName'] = $GPOCache[$Search].DisplayName
|
||||
$Output['DomainName'] = $GPOCache[$Search].DomainName
|
||||
$Output['Owner'] = $GPOCache[$Search].Owner
|
||||
$Output['GpoStatus'] = $GPOCache[$Search].GpoStatus
|
||||
$Output['Description'] = $GPOCache[$Search].Description
|
||||
$Output['CreationTime'] = $GPOCache[$Search].CreationTime
|
||||
$Output['ModificationTime'] = $GPOCache[$Search].ModificationTime
|
||||
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $DN -ToDC
|
||||
$Output['GPODistinguishedName'] = $DN
|
||||
# This is object name, usually used for sites
|
||||
$Output['Name'] = $Object.Name
|
||||
[PSCustomObject] $Output
|
||||
} else {
|
||||
Write-Warning "Get-PrivGPOZaurrLink - Couldn't find link $Search in a GPO Cache. Lack of permissions for given GPO? Are you running as admin? Skipping."
|
||||
}
|
||||
} else {
|
||||
$Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $DN -ToDC
|
||||
$Output['GPODistinguishedName'] = $DN
|
||||
[PSCustomObject] $Output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+116
-62
@@ -9,25 +9,67 @@
|
||||
[string] $Splitter = [System.Environment]::NewLine,
|
||||
[switch] $ReturnObject,
|
||||
[System.Collections.IDictionary] $ExcludeGroupPolicies,
|
||||
[string[]] $Type
|
||||
[string[]] $Type,
|
||||
[System.Collections.IDictionary] $LinksSummaryCache
|
||||
)
|
||||
if ($XMLContent.GPO.LinksTo) {
|
||||
$LinkSplit = ([Array] $XMLContent.GPO.LinksTo).Where( { $_.Enabled -eq $true }, 'Split')
|
||||
[Array] $LinksEnabled = $LinkSplit[0]
|
||||
[Array] $LinksDisabled = $LinkSplit[1]
|
||||
$LinksEnabledCount = $LinksEnabled.Count
|
||||
$LinksDisabledCount = $LinksDisabled.Count
|
||||
$LinksTotalCount = ([Array] $XMLContent.GPO.LinksTo).Count
|
||||
if ($LinksEnabledCount -eq 0) {
|
||||
$Linked = $false
|
||||
|
||||
$DisplayName = $XMLContent.GPO.Name
|
||||
$DomainName = $XMLContent.GPO.Identifier.Domain.'#text'
|
||||
|
||||
if ($LinksSummaryCache) {
|
||||
$SearchGUID = -join ($XMLContent.GPO.Identifier.Domain.'#text', $XMLContent.GPO.Identifier.Identifier.InnerText -replace '{' -replace '}')
|
||||
if ($LinksSummaryCache[$SearchGUID]) {
|
||||
$Linked = $LinksSummaryCache[$SearchGUID].Linked
|
||||
$LinksEnabledCount = $LinksSummaryCache[$SearchGUID].LinksEnabledCount
|
||||
$LinksDisabledCount = $LinksSummaryCache[$SearchGUID].LinksDisabledCount
|
||||
$LinksTotalCount = $LinksSummaryCache[$SearchGUID].LinksCount
|
||||
$Links = $LinksSummaryCache[$SearchGUID].Links
|
||||
$LinksObjects = $LinksSummaryCache[$SearchGUID].LinksObjects
|
||||
} else {
|
||||
$Linked = $true
|
||||
$Linked = $false
|
||||
$LinksEnabledCount = 0
|
||||
$LinksDisabledCount = 0
|
||||
$LinksTotalCount = 0
|
||||
$Links = $null
|
||||
$LinksObjects = $null
|
||||
}
|
||||
} else {
|
||||
$Linked = $false
|
||||
$LinksEnabledCount = 0
|
||||
$LinksDisabledCount = 0
|
||||
$LinksTotalCount = 0
|
||||
if ($XMLContent.GPO.LinksTo) {
|
||||
$LinkSplit = ([Array] $XMLContent.GPO.LinksTo).Where( { $_.Enabled -eq $true }, 'Split')
|
||||
[Array] $LinksEnabled = $LinkSplit[0]
|
||||
[Array] $LinksDisabled = $LinkSplit[1]
|
||||
$LinksEnabledCount = $LinksEnabled.Count
|
||||
$LinksDisabledCount = $LinksDisabled.Count
|
||||
$LinksTotalCount = ([Array] $XMLContent.GPO.LinksTo).Count
|
||||
if ($LinksEnabledCount -eq 0) {
|
||||
$Linked = $false
|
||||
} else {
|
||||
$Linked = $true
|
||||
}
|
||||
$Links = @(
|
||||
$XMLContent.GPO.LinksTo | ForEach-Object -Process {
|
||||
if ($_) {
|
||||
$_.SOMPath
|
||||
}
|
||||
}
|
||||
) -join $Splitter
|
||||
$LinksObjects = $XMLContent.GPO.LinksTo | ForEach-Object -Process {
|
||||
if ($_) {
|
||||
[PSCustomObject] @{
|
||||
CanonicalName = $_.SOMPath
|
||||
Enabled = $_.Enabled
|
||||
NoOverride = $_.NoOverride
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$Linked = $false
|
||||
$LinksEnabledCount = 0
|
||||
$LinksDisabledCount = 0
|
||||
$LinksTotalCount = 0
|
||||
$Links = $null
|
||||
$LinksObjects = $null
|
||||
}
|
||||
}
|
||||
# Find proper values for enabled/disabled user/computer settings
|
||||
if ($XMLContent.GPO.Computer.Enabled -eq 'False') {
|
||||
@@ -35,7 +77,7 @@
|
||||
} elseif ($XMLContent.GPO.Computer.Enabled -eq 'True') {
|
||||
$ComputerEnabled = $true
|
||||
} else {
|
||||
Write-Warning "Get-XMLGPO - Computer enabled not set to true or false. Weird."
|
||||
Write-Warning "Get-XMLGPO - Computer enabled not set to true or false [$DisplayName/$DomainName]. Weird."
|
||||
$ComputerEnabled = $null
|
||||
}
|
||||
if ($XMLContent.GPO.User.Enabled -eq 'False') {
|
||||
@@ -43,7 +85,7 @@
|
||||
} elseif ($XMLContent.GPO.User.Enabled -eq 'True') {
|
||||
$UserEnabled = $true
|
||||
} else {
|
||||
Write-Warning "Get-XMLGPO - User enabled not set to true or false. Weird."
|
||||
Write-Warning "Get-XMLGPO - User enabled not set to true or false [$DisplayName/$DomainName] . Weird."
|
||||
$UserEnabled = $null
|
||||
}
|
||||
# Translate Enabled to same as GPO GUI
|
||||
@@ -62,8 +104,8 @@
|
||||
}
|
||||
|
||||
# This is kind of old way of doing things, but it's superseded by other way below
|
||||
$ComputerSettingsAvailable = if ($null -eq $XMLContent.GPO.Computer.ExtensionData) { $false } else { $true }
|
||||
$UserSettingsAvailable = if ($null -eq $XMLContent.GPO.User.ExtensionData) { $false } else { $true }
|
||||
[bool] $ComputerSettingsAvailable = if ($null -eq $XMLContent.GPO.Computer.ExtensionData) { $false } else { $true }
|
||||
[bool] $UserSettingsAvailable = if ($null -eq $XMLContent.GPO.User.ExtensionData) { $false } else { $true }
|
||||
|
||||
if ($ComputerSettingsAvailable -eq $false -and $UserSettingsAvailable -eq $false) {
|
||||
$NoSettings = $true
|
||||
@@ -74,35 +116,58 @@
|
||||
# $OutputUser = $XMLContent.GPO.User.ExtensionData.Extension | Where-Object { $_.PSObject.Properties.TypeNameOfValue -in 'System.Xml.XmlElement', 'System.Object[]' }
|
||||
# $OutputComputer = $XMLContent.GPO.Computer.ExtensionData.Extension | Where-Object { $_.PSObject.Properties.TypeNameOfValue -in 'System.Xml.XmlElement', 'System.Object[]' }
|
||||
|
||||
$OutputUser = foreach ($ExtensionType in $XMLContent.GPO.User.ExtensionData.Extension) {
|
||||
if ($ExtensionType) {
|
||||
$GPOSettingTypeSplit = ($ExtensionType.type -split ':')
|
||||
try {
|
||||
$KeysToLoop = $ExtensionType | Get-Member -MemberType Properties -ErrorAction Stop | Where-Object { $_.Name -notin 'type', $GPOSettingTypeSplit[0] -and $_.Name -notin @('Blocked') }
|
||||
} catch {
|
||||
Write-Warning "Get-XMLGPO - things went sideways $($_.Exception.Message)"
|
||||
continue
|
||||
}
|
||||
|
||||
# This is additional check we do for error check to prevent false-positives for EMPTY on non-english language
|
||||
$PreCheckOutputUser = $false
|
||||
$PreCheckOutputComputer = $false
|
||||
foreach ($Extension in $XMLContent.GPO.User.ExtensionData) {
|
||||
if ($Extension.Error) {
|
||||
$PreCheckOutputUser = $true
|
||||
}
|
||||
$KeysToLoop
|
||||
}
|
||||
$OutputComputer = foreach ($ExtensionType in $XMLContent.GPO.Computer.ExtensionData.Extension) {
|
||||
if ($ExtensionType) {
|
||||
$GPOSettingTypeSplit = ($ExtensionType.type -split ':')
|
||||
try {
|
||||
$KeysToLoop = $ExtensionType | Get-Member -MemberType Properties -ErrorAction Stop | Where-Object { $_.Name -notin 'type', $GPOSettingTypeSplit[0] -and $_.Name -notin @('Blocked') }
|
||||
} catch {
|
||||
Write-Warning "Get-XMLGPO - things went sideways $($_.Exception.Message)"
|
||||
continue
|
||||
}
|
||||
foreach ($Extension in $XMLContent.GPO.Computer.ExtensionData) {
|
||||
if ($Extension.Error) {
|
||||
$PreCheckOutputComputer = $true
|
||||
}
|
||||
$KeysToLoop
|
||||
}
|
||||
if ($PreCheckOutputComputer -eq $true -or $PreCheckOutputUser -eq $true) {
|
||||
# in some cases GPResult seems to return an error - this was first noticed by user when using Dutch based system
|
||||
# I am not sure if it's possible to fix this error for users, but once that happens checking if GPO is empty fails using the method below
|
||||
# therefore we will use the old method of assuming something is empty or not empty in such case
|
||||
Write-Warning "Get-XMLGPO - Reading GPO content [$DisplayName/$DomainName] returned an error. This may be because of non-english language. Assesing EMPTY using old method which can report false positives. Be careful please."
|
||||
$OutputUser = @()
|
||||
$OutputComputer = @()
|
||||
} else {
|
||||
[Array] $OutputUser = foreach ($ExtensionType in $XMLContent.GPO.User.ExtensionData.Extension) {
|
||||
if ($ExtensionType) {
|
||||
$GPOSettingTypeSplit = ($ExtensionType.type -split ':')
|
||||
try {
|
||||
$KeysToLoop = $ExtensionType | Get-Member -MemberType Properties -ErrorAction Stop | Where-Object { $_.Name -notin 'type', $GPOSettingTypeSplit[0] -and $_.Name -notin @('Blocked') }
|
||||
} catch {
|
||||
Write-Warning "Get-XMLGPO - things went sideways [$DisplayName/$DomainName]. Error $($_.Exception.Message)"
|
||||
continue
|
||||
}
|
||||
}
|
||||
$KeysToLoop
|
||||
}
|
||||
[Array] $OutputComputer = foreach ($ExtensionType in $XMLContent.GPO.Computer.ExtensionData.Extension) {
|
||||
if ($ExtensionType) {
|
||||
$GPOSettingTypeSplit = ($ExtensionType.type -split ':')
|
||||
try {
|
||||
$KeysToLoop = $ExtensionType | Get-Member -MemberType Properties -ErrorAction Stop | Where-Object { $_.Name -notin 'type', $GPOSettingTypeSplit[0] -and $_.Name -notin @('Blocked') }
|
||||
} catch {
|
||||
Write-Warning "Get-XMLGPO - things went sideways [$DisplayName/$DomainName]. Error $($_.Exception.Message)"
|
||||
continue
|
||||
}
|
||||
}
|
||||
$KeysToLoop
|
||||
}
|
||||
|
||||
[bool] $ComputerSettingsAvailable = if ($OutputComputer.Count -gt 0) { $true } else { $false }
|
||||
[bool] $UserSettingsAvailable = if ($OutputUser.Count -gt 0) { $true } else { $false }
|
||||
}
|
||||
|
||||
$ComputerSettingsAvailable = if ($OutputComputer) { $true } else { $false }
|
||||
$UserSettingsAvailable = if ($OutputUser) { $true } else { $false }
|
||||
|
||||
if (-not $ComputerSettingsAvailable -and -not $UserSettingsAvailable) {
|
||||
if ($ComputerSettingsAvailable -eq $false -and $UserSettingsAvailable -eq $false) {
|
||||
$Empty = $true
|
||||
} else {
|
||||
$Empty = $false
|
||||
@@ -166,7 +231,8 @@
|
||||
$Exclude = $false
|
||||
if ($ExcludeGroupPolicies) {
|
||||
$PolicyWithDomain = -join ($XMLContent.GPO.Identifier.Domain.'#text', $XMLContent.GPO.Name)
|
||||
if ($ExcludeGroupPolicies[$XMLContent.GPO.Name] -or $ExcludeGroupPolicies[$PolicyWithDomain]) {
|
||||
$PolicyWithDomainID = -join ($XMLContent.GPO.Identifier.Domain.'#text', $XMLContent.GPO.Identifier.Identifier.'#text')
|
||||
if ($ExcludeGroupPolicies[$XMLContent.GPO.Name] -or $ExcludeGroupPolicies[$PolicyWithDomain] -or $ExcludeGroupPolicies[$PolicyWithDomainID] -or $ExcludeGroupPolicies[$XMLContent.GPO.Identifier.Identifier.'#text']) {
|
||||
$Exclude = $true
|
||||
}
|
||||
}
|
||||
@@ -217,6 +283,7 @@
|
||||
'DisplayName' = $XMLContent.GPO.Name
|
||||
'DomainName' = $XMLContent.GPO.Identifier.Domain.'#text'
|
||||
'GUID' = $XMLContent.GPO.Identifier.Identifier.InnerText -replace '{' -replace '}'
|
||||
'Days' = (New-TimeSpan -Start ([DateTime] $XMLContent.GPO.ModifiedTime) -End (Get-Date)).Days
|
||||
'Empty' = $Empty
|
||||
'Linked' = $Linked
|
||||
'Enabled' = $EnabledBool
|
||||
@@ -224,6 +291,7 @@
|
||||
'Problem' = $Problem
|
||||
'ApplyPermission' = $null
|
||||
'Exclude' = $Exclude
|
||||
'Description' = $GPO.Description
|
||||
'ComputerPolicies' = $XMLContent.GPO.Computer.ExtensionData.Name -join ", "
|
||||
'UserPolicies' = $XMLContent.GPO.User.ExtensionData.Name -join ", "
|
||||
'LinksCount' = $LinksTotalCount
|
||||
@@ -238,8 +306,8 @@
|
||||
'UserSettingsAvailable' = $UserSettingsAvailable
|
||||
#'ComputerSettingsAvailableReal' = $ComputerSettingsAvailableReal
|
||||
#'UserSettingsAvailableReal' = $UserSettingsAvailableReal
|
||||
'ComputerSettingsTypes' = $OutputComputer.Name
|
||||
'UserSettingsTypes' = $OutputUser.Name
|
||||
'ComputerSettingsTypes' = $OutputComputer.Name -join ", "
|
||||
'UserSettingsTypes' = $OutputUser.Name -join ", "
|
||||
'ComputerEnabled' = $ComputerEnabled
|
||||
'UserEnabled' = $UserEnabled
|
||||
'ComputerSettingsStatus' = if ($XMLContent.GPO.Computer.VersionDirectory -eq 0 -and $XMLContent.GPO.Computer.VersionSysvol -eq 0) { "NeverModified" } else { "Modified" }
|
||||
@@ -280,22 +348,8 @@
|
||||
}
|
||||
)
|
||||
'Auditing' = if ($XMLContent.GPO.SecurityDescriptor.AuditingPresent.'#text' -eq 'true') { $true } else { $false }
|
||||
'Links' = @(
|
||||
$XMLContent.GPO.LinksTo | ForEach-Object -Process {
|
||||
if ($_) {
|
||||
$_.SOMPath
|
||||
}
|
||||
}
|
||||
) -join $Splitter
|
||||
'LinksObjects' = $XMLContent.GPO.LinksTo | ForEach-Object -Process {
|
||||
if ($_) {
|
||||
[PSCustomObject] @{
|
||||
CanonicalName = $_.SOMPath
|
||||
Enabled = $_.Enabled
|
||||
NoOverride = $_.NoOverride
|
||||
}
|
||||
}
|
||||
}
|
||||
'Links' = $Links
|
||||
'LinksObjects' = $LinksObjects
|
||||
'GPOObject' = $GPO
|
||||
}
|
||||
if ($GPOOutput.ACL) {
|
||||
|
||||
@@ -4,19 +4,231 @@
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrInheritance -IncludeBlockedObjects -OnlyBlockedInheritance -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
if ($Script:Reporting['GPOBlockedInheritance']['Exclusions']) {
|
||||
Get-GPOZaurrInheritance -IncludeBlockedObjects -IncludeExcludedObjects -OnlyBlockedInheritance -IncludeGroupPoliciesForBlockedObjects -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $Excludeomains -Exclusions $Script:Reporting['GPOBlockedInheritance']['Exclusions']
|
||||
} else {
|
||||
Get-GPOZaurrInheritance -IncludeBlockedObjects -IncludeExcludedObjects -OnlyBlockedInheritance -IncludeGroupPoliciesForBlockedObjects -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $Excludeomains
|
||||
}
|
||||
}
|
||||
Processing = {
|
||||
foreach ($GPO in $Script:Reporting['GPOBlockedInheritance']['Data']) {
|
||||
if (-not $Script:Reporting['GPOBlockedInheritance']['Variables']['DeletionHarmlessPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['DeletionHarmlessPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOBlockedInheritance']['Variables']['RequiresInvesigationPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['RequiresInvesigationPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if ($GPO.Exclude -eq $true) {
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['Exclude']++
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['UsersAffectedExclude'] = $Script:Reporting['GPOBlockedInheritance']['Variables']['UsersAffectedExclude'] + $GPO.UsersCount
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['ComputersAffectedExclude'] = $Script:Reporting['GPOBlockedInheritance']['Variables']['ComputersAffectedExclude'] + $GPO.ComputersCount
|
||||
} else {
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['UsersAffected'] = $Script:Reporting['GPOBlockedInheritance']['Variables']['UsersAffected'] + $GPO.UsersCount
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['ComputersAffected'] = $Script:Reporting['GPOBlockedInheritance']['Variables']['ComputersAffected'] + $GPO.ComputersCount
|
||||
}
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['UsersAffectedIncludingExclude'] = $Script:Reporting['GPOBlockedInheritance']['Variables']['UsersAffectedIncludingExclude'] + $GPO.UsersCount
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['ComputersAffectedIncludingExclude'] = $Script:Reporting['GPOBlockedInheritance']['Variables']['ComputersAffectedIncludingExclude'] + $GPO.ComputersCount
|
||||
|
||||
if ($GPO.Exclude -eq $false -and ($GPO.UsersCount -gt 0 -or $GPO.ComputersCount -gt 0)) {
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['RequiresInvesigation']++
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['RequiresInvesigationPerDomain'][$GPO.DomainName]++
|
||||
}
|
||||
if ($GPO.Exclude -eq $false -and ($GPO.UsersCount -eq 0 -and $GPO.ComputersCount -eq 0)) {
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['DeletionHarmless']++
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['DeletionHarmlessPerDomain'][$GPO.DomainName]++
|
||||
}
|
||||
# add gpo from blocked inheritance to create additional table
|
||||
#foreach ($GpoBlocked in $Script:Reporting['GPOBlockedInheritance']['Data'].GroupPolicies) {
|
||||
#$Script:Reporting['GPOBlockedInheritance']['Variables']['GroupPolicies'].Add($GpoBlocked)
|
||||
#}
|
||||
}
|
||||
if ($Script:Reporting['GPOBlockedInheritance']['Variables']['RequiresInvesigation'] -gt 0 -or $Script:Reporting['GPOBlockedInheritance']['Variables']['DeletionHarmless'] -gt 0) {
|
||||
$Script:Reporting['GPOBlockedInheritance']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPOBlockedInheritance']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Resources = @(
|
||||
'http://www.firewall.cx/microsoft-knowledgebase/windows-2012/1056-windows-2012-group-policy-enforcement.html'
|
||||
)
|
||||
Variables = @{
|
||||
|
||||
Total = 0
|
||||
Exclude = 0
|
||||
RequiresInvesigation = 0
|
||||
RequiresInvesigationPerDomain = [ordered] @{}
|
||||
DeletionHarmless = 0
|
||||
DeletionHarmlessPerDomain = [ordered] @{}
|
||||
UsersAffected = 0
|
||||
UsersAffectedExclude = 0
|
||||
UsersAffectedIncludingExclude = 0
|
||||
ComputersAffected = 0
|
||||
ComputersAffectedIncludingExclude = 0
|
||||
ComputersAffectedExclude = 0
|
||||
GroupPolicies = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Summary = {
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"By default, group policy settings that are linked to parent objects are inherited to the child objects in the active directory hierarchy. "
|
||||
"By default, Default Domain Policy is linked to the domain and is inherited to all the child objects of the domain hierarchy. "
|
||||
"So does any other policies linked to the top level OU's. "
|
||||
}
|
||||
New-HTMLText -Text "Blocked Inheritance" -FontSize 10pt -FontWeight bold
|
||||
New-HTMLText -FontSize 10pt -Text @(
|
||||
"As GPOs can be inherited by default, they can also be blocked, if required using the Block Inheritance. "
|
||||
"If the Block Inheritance setting is enabled, the inheritance of group policy setting is blocked. "
|
||||
"This setting is mostly used when the OU contains users or computers that require different settings than what is applied to the domain level. "
|
||||
"Unfortunetly blocking inheritance can have serious security consequences. "
|
||||
)
|
||||
New-HTMLText -Text @(
|
||||
'As it stands currently there are ',
|
||||
$Script:Reporting['GPOBlockedInheritance']['Data'].Count,
|
||||
' organisational units with '
|
||||
'GPO Inheritance Block'
|
||||
' out of which '
|
||||
$Script:Reporting['GPOBlockedInheritance']['Variables']['Exclude'],
|
||||
' are marked as Excluded '
|
||||
'(approved by IT). '
|
||||
) -FontSize 10pt -FontWeight normal, bold, normal, bold, normal, bold, normal, bold -LineBreak
|
||||
if ($Script:Reporting['GPOBlockedInheritance']['Data'].Count -ne 0) {
|
||||
New-HTMLText -Text 'Users & Computers affected by inheritance blocks:' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text $Script:Reporting['GPOBlockedInheritance']['Variables']['UsersAffected'], ' users affected due to inheritance blocks' -FontWeight bold, normal
|
||||
New-HTMLListItem -Text $Script:Reporting['GPOBlockedInheritance']['Variables']['UsersAffectedExclude'], ' users affected, but approved/excluded, due to inheritance blocks' -FontWeight bold, normal
|
||||
New-HTMLListItem -Text $Script:Reporting['GPOBlockedInheritance']['Variables']['ComputersAffected'], ' computers affected due to inheritance blocks' -FontWeight bold, normal
|
||||
New-HTMLListItem -Text $Script:Reporting['GPOBlockedInheritance']['Variables']['ComputersAffectedExclude'], ' computers affected, but approved/excluded, due to inheritance blocks' -FontWeight bold, normal
|
||||
} -FontSize 10pt
|
||||
|
||||
New-HTMLText -Text 'Following domains require:' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOBlockedInheritance']['Variables']['RequiresInvesigationPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain proposes ", $Script:Reporting['GPOBlockedInheritance']['Variables']['RequiresInvesigationPerDomain'][$Domain], " investigation (computers or users inside)." -FontWeight normal, bold, normal
|
||||
New-HTMLListItem -Text "$Domain proposes ", $Script:Reporting['GPOBlockedInheritance']['Variables']['DeletionHarmlessPerDomain'][$Domain], " removal (mostly harmless due to no computers or users inside)." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
}
|
||||
New-HTMLText -FontSize 10pt -Text "Please review output in table and follow the steps below table to get Active Directory Group Policies in healthy state."
|
||||
|
||||
if ($Script:Reporting['GPOBlockedInheritance']['Exclusions']) {
|
||||
New-HTMLText -LineBreak
|
||||
New-HTMLText -Text @(
|
||||
"While preparing this report following exclusions were defined. "
|
||||
"Please make sure that when you execute your steps to include those exclusions to prevent any issues. "
|
||||
) -FontSize 10pt -FontWeight bold, normal -Color Red, None -LineBreak
|
||||
|
||||
New-HTMLText -Text "Code to use for exclusions: " -FontSize 10pt -FontWeight bold -LineBreak
|
||||
|
||||
$Code = New-GPOZaurrExclusions -ExclusionsArray $Script:Reporting['GPOBlockedInheritance']['Exclusions']
|
||||
|
||||
if ($Code) {
|
||||
New-HTMLCodeBlock -Code $Code -Style powershell
|
||||
}
|
||||
}
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOBlockedInheritance']['Data'] -Filtering
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
& $Script:GPOConfiguration['GPOBlockedInheritance']['Summary']
|
||||
}
|
||||
New-HTMLPanel {
|
||||
New-HTMLChart {
|
||||
New-ChartLegend -Names 'Affected', 'Affected, but excluded' -Color Salmon, PaleGreen
|
||||
New-ChartBarOptions -Type barStacked
|
||||
New-ChartBar -Name 'Users' -Value $Script:Reporting['GPOBlockedInheritance']['Variables']['UsersAffected'], $Script:Reporting['GPOBlockedInheritance']['Variables']['UsersAffectedExclude']
|
||||
New-ChartBar -Name 'Computers' -Value $Script:Reporting['GPOBlockedInheritance']['Variables']['ComputersAffected'], $Script:Reporting['GPOBlockedInheritance']['Variables']['ComputersAffectedExclude']
|
||||
} -Title 'Users & Computers affected due to blocked inheritance' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Organizational Units with Group Policy Blocked Inheritance' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOBlockedInheritance']['Data'] -Filtering {
|
||||
New-TableEvent -TableID 'TableWithGroupPoliciesBlockedInheritance' -SourceColumnID 8 -TargetColumnID 9
|
||||
New-HTMLTableCondition -Name 'Exclude' -Value $true -BackgroundColor DeepSkyBlue -ComparisonType string -Row
|
||||
New-TableConditionGroup {
|
||||
New-TableCondition -Name 'BlockedInheritance' -Value $true
|
||||
New-TableCondition -Name 'Exclude' -Value $false
|
||||
} -BackgroundColor Salmon -FailBackgroundColor SpringGreen -HighlightHeaders 'BlockedInheritance', 'Exclude'
|
||||
New-TableConditionGroup {
|
||||
New-TableCondition -Name 'UsersCount' -Value 0
|
||||
New-TableCondition -Name 'ComputersCount' -Value 0
|
||||
} -BackgroundColor Salmon -FailBackgroundColor Amber -HighlightHeaders 'UsersCount', 'ComputersCount'
|
||||
New-TableColumnOption -Hidden $true -ColumnIndex 8
|
||||
} -PagingOptions 5, 10, 20, 30, 40, 50 -ExcludeProperty GroupPolicies
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policies affecting objects in Organizational Units with Blocked Inheritance' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOBlockedInheritance']['Data'].GroupPolicies -Filtering {
|
||||
New-TableCondition -Name 'Enabled' -Value $true -BackgroundColor SpringGreen -FailBackgroundColor Salmon
|
||||
New-TableCondition -Name 'Enforced' -Value $true -BackgroundColor Amber -FailBackgroundColor AirForceBlue
|
||||
New-TableCondition -Name 'LinkedDirectly' -Value $true -BackgroundColor Amber -FailBackgroundColor AirForceBlue
|
||||
} -PagingOptions 5, 10, 20, 30, 40, 50 -DataTableID 'TableWithGroupPoliciesBlockedInheritance'
|
||||
}
|
||||
if ($Script:Reporting['Settings']['HideSteps'] -eq $false) {
|
||||
New-HTMLSection -Name 'Steps to fix - Organizational Units with Group Policy Blocked Inheritance' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLWizard {
|
||||
New-HTMLWizardStep -Name 'Prepare environment' {
|
||||
New-HTMLText -Text "To be able to execute actions in automated way please install required modules. Those modules will be installed straight from Microsoft PowerShell Gallery."
|
||||
New-HTMLCodeBlock -Code {
|
||||
Install-Module GPOZaurr -Force
|
||||
Import-Module GPOZaurr -Force
|
||||
} -Style powershell
|
||||
New-HTMLText -Text "Using force makes sure newest version is downloaded from PowerShellGallery regardless of what is currently installed. Once installed you're ready for next step."
|
||||
}
|
||||
if ($Script:Reporting['GPOBlockedInheritance']['Exclusions']) {
|
||||
New-HTMLWizardStep -Name 'Required exclusions' {
|
||||
New-HTMLText -Text @(
|
||||
"While preparing this report following exclusions were defined. "
|
||||
"Please make sure that when you execute your steps to include those exclusions to prevent any issues. "
|
||||
)
|
||||
$Code = New-GPOZaurrExclusions -ExclusionsArray $Script:Reporting['GPOBlockedInheritance']['Exclusions']
|
||||
|
||||
if ($Code) {
|
||||
New-HTMLCodeBlock -Code $Code -Style powershell
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Prepare report' {
|
||||
New-HTMLText -Text @(
|
||||
"Depending when this report was run you may want to prepare new report before proceeding removing Group Policy Inheritance Blocks. "
|
||||
"Please keep in mind that if exclusions for some Organizational OU's were defined you need to pass them to cmdlet below to not remove approved GPO Inheritance Blocks. "
|
||||
"To generate new report please use:"
|
||||
)
|
||||
New-HTMLCodeBlock -Code {
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrBlockedGPOInheritanceBefore.html -Verbose -Type GPOBlockedInheritance
|
||||
}
|
||||
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-GPOZaurrInheritance -IncludeBlockedObjects -IncludeExcludedObjects -OnlyBlockedInheritance
|
||||
$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 OU GPO Inheritance Blocks' {
|
||||
New-HTMLText -Text @(
|
||||
"Removing inheritance blocks is quite trivial and can be done from GPO GUI. However knowing when to remove is the important part. "
|
||||
"Please consult other Domain Admins before removing any inheritance blocks, and either approve exclusion or remove blocking inheritance. "
|
||||
)
|
||||
}
|
||||
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\GPOZaurrBlockedGPOInheritanceAfter.html -Verbose -Type GPOBlockedInheritance
|
||||
}
|
||||
New-HTMLText -Text "If everything is healthy in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOBlockedInheritance']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOBlockedInheritance']['WarningsAndErrors'] -Filtering {
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
$GPOZaurrBrokenLink = [ordered] @{
|
||||
Name = 'Group Policy Broken Links'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrBrokenLink -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
}
|
||||
Processing = {
|
||||
$Script:Reporting['GPOBrokenLink']['Variables']['RequireDeletion'] = $Script:Reporting['GPOBrokenLink']['Data'].Count
|
||||
$Script:Reporting['GPOBrokenLink']['Variables']['WillFixPerDomain'] = @{}
|
||||
$Script:Reporting['GPOBrokenLink']['Variables']['Unique'] = @{}
|
||||
foreach ($Link In $Script:Reporting['GPOBrokenLink']['Data']) {
|
||||
$DomainName = ConvertFrom-DistinguishedName -ToDomainCN -DistinguishedName $Link.DistinguishedName
|
||||
# Create Per Domain Variables
|
||||
if (-not $Script:Reporting['GPOBrokenLink']['Variables']['WillFixPerDomain'][$DomainName]) {
|
||||
$Script:Reporting['GPOBrokenLink']['Variables']['WillFixPerDomain'][$DomainName] = 0
|
||||
}
|
||||
$Script:Reporting['GPOBrokenLink']['Variables']['WillFixPerDomain'][$DomainName]++
|
||||
# Lets do unique OU counting
|
||||
$Script:Reporting['GPOBrokenLink']['Variables']['Unique'][$Link.CanonicalName] = $Link
|
||||
}
|
||||
$Script:Reporting['GPOBrokenLink']['Variables']['UniqueObjects'] = $Script:Reporting['GPOBrokenLink']['Variables']['Unique'].Keys
|
||||
|
||||
if ($Script:Reporting['GPOBrokenLink']['Data'].Count -gt 0) {
|
||||
$Script:Reporting['GPOBrokenLink']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPOBrokenLink']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = @{
|
||||
RequireDeletion = 0
|
||||
WillFixPerDomain = $null
|
||||
UniqueObjects = $null
|
||||
Unique = $null
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Summary = {
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"When GPO is deleted correctly, it usually is removed from AD, SYSVOL, and any link to it is also discarded. "
|
||||
"Unfortunately, this is true only if the GPO is created and linked within the same domain. "
|
||||
"If GPO is linked in another domain, this leaves a broken link hanging on before it was linked. "
|
||||
"Additionally, the Remove-GPO cmdlet doesn't handle site link deletions, which causes dead links to be stuck on sites until those are manually deleted. "
|
||||
"This means that any GPOs deleted using PowerShell may leave a trail."
|
||||
}
|
||||
New-HTMLText -Text @(
|
||||
'As it stands currently there are ',
|
||||
$Script:Reporting['GPOBrokenLink']['Data'].Count,
|
||||
' broken links that need to be deleted over '
|
||||
$Script:Reporting['GPOBrokenLink']['Variables']['UniqueObjects'].Count,
|
||||
' unique objects. '
|
||||
) -FontSize 10pt -FontWeight normal, bold, normal, bold, normal -LineBreak
|
||||
if ($Script:Reporting['GPOBrokenLink']['Data'].Count -ne 0) {
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOBrokenLink']['Variables']['WillFixPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOBrokenLink']['Variables']['WillFixPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
}
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
& $Script:GPOConfiguration['GPOBrokenLink']['Summary']
|
||||
}
|
||||
New-HTMLPanel {
|
||||
New-HTMLChart {
|
||||
New-ChartLegend -Names 'Bad' -Color Salmon
|
||||
New-ChartBar -Name 'Broken Links' -Value $Script:Reporting['GPOBrokenLink']['Data'].Count
|
||||
} -Title 'Broken Links' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policy Broken Links' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOBrokenLink']['Data'] -Filtering {
|
||||
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
if ($Script:Reporting['Settings']['HideSteps'] -eq $false) {
|
||||
New-HTMLSection -Name 'Steps to remove Broken Links' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLWizard {
|
||||
New-HTMLWizardStep -Name 'Prepare environment' {
|
||||
New-HTMLText -Text "To be able to execute actions in automated way please install required modules. Those modules will be installed straight from Microsoft PowerShell Gallery."
|
||||
New-HTMLCodeBlock -Code {
|
||||
Install-Module GPOZaurr -Force
|
||||
Import-Module GPOZaurr -Force
|
||||
} -Style powershell
|
||||
New-HTMLText -Text "Using force makes sure newest version is downloaded from PowerShellGallery regardless of what is currently installed. Once installed you're ready for next step."
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Prepare report' {
|
||||
New-HTMLText -Text "Depending when this report was run you may want to prepare new report before proceeding fixing GPO links. To generate new report please use:"
|
||||
New-HTMLCodeBlock -Code {
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrBrokenLinkBefore.html -Verbose -Type GPOBrokenLink
|
||||
}
|
||||
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-GPOZaurrBrokenLink -Verbose
|
||||
$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 Broken Links' {
|
||||
New-HTMLText -Text "Following command when executed, runs internally command that lists all broken links. After finding them all it delets them according to given criteria. "
|
||||
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-GPOZaurrBrokenLink -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 {
|
||||
Repair-GPOZaurrBrokenLink -Verbose -LimitProcessing 2
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed removes only first X number of links. Keep in mind that 5 broken links on a single Organizational Unit are treated as one. 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\GPOZaurrBrokenLinkAfter.html -Verbose -Type GPOBrokenLink
|
||||
}
|
||||
New-HTMLText -Text "If everything is healthy in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOBrokenLink']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOBrokenLink']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,11 +52,12 @@
|
||||
}
|
||||
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. "
|
||||
"When GPO is created, it creates an entry in Active Directory (metadata) and SYSVOL (content). "
|
||||
"Two different places mean two different sets of permissions. "
|
||||
"The group Policy module is making sure the data in both places is correct. "
|
||||
"However, it's not necessarily the case for different reasons, and often permissions go out of sync between AD and SYSVOL. "
|
||||
"This test verifies the 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 is 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 {
|
||||
@@ -111,10 +112,10 @@
|
||||
New-HTMLCodeBlock -Code {
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrPermissionsInconsistentBefore.html -Verbose -Type GPOConsistency
|
||||
}
|
||||
New-HTMLText -Text {
|
||||
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
|
||||
@@ -143,8 +144,12 @@
|
||||
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-HTMLText -Text @(
|
||||
"Unfortunetly this step is manual until automation is developed. "
|
||||
"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."
|
||||
"Please keep in mind that it's possible inconsistent downlevel permissions fix will not be required once the top level fix is applied. "
|
||||
"Rerun report to find out if you've just fixed top-level permissions. "
|
||||
)
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Verification report' {
|
||||
New-HTMLText -TextBlock {
|
||||
@@ -155,7 +160,7 @@
|
||||
}
|
||||
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
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
New-HTMLCodeBlock -Code {
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrDuplicateObjectsBefore.html -Verbose -Type GPODuplicates
|
||||
}
|
||||
New-HTMLText -Text {
|
||||
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. "
|
||||
}
|
||||
@@ -106,7 +106,7 @@
|
||||
}
|
||||
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
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
$GPOZaurrLinks = [ordered] @{
|
||||
Name = 'Group Policy Links'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrLink -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -Summary
|
||||
}
|
||||
Processing = {
|
||||
|
||||
}
|
||||
Variables = @{
|
||||
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOLinks']['Data'] -Filtering
|
||||
if ($Script:Reporting['GPOLinks']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOLinks']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+140
-63
@@ -4,9 +4,8 @@
|
||||
Action = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
if ($Script:Reporting['GPOList']['ExclusionsCode']) {
|
||||
Get-GPOZaurr -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExcludeGroupPolicies $Script:Reporting['GPOList']['ExclusionsCode']
|
||||
|
||||
if ($Script:Reporting['GPOList']['Exclusions']) {
|
||||
Get-GPOZaurr -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExcludeGroupPolicies $Script:Reporting['GPOList']['Exclusions']
|
||||
} else {
|
||||
Get-GPOZaurr -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
}
|
||||
@@ -47,7 +46,24 @@
|
||||
if (-not $Script:Reporting['GPOList']['Variables']['GPOApplypermissionNoPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOList']['Variables']['GPOApplypermissionNoPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if ($GPO.Enabled -eq $false -or $GPO.Empty -eq $true -or $GPO.Linked -eq $false -or $GPO.ApplyPermission -eq $false) {
|
||||
|
||||
if ($GPO.Days -le $Script:Reporting['GPOList']['Variables']['GPOOlderThan']) {
|
||||
# Skip GPOS that are younger than 30 days
|
||||
$Script:Reporting['GPOList']['Variables']['GPOSkip']++
|
||||
}
|
||||
if ($GPO.Exclude -eq $true) {
|
||||
# Skip GPOS that are excluded
|
||||
$Script:Reporting['GPOList']['Variables']['GPOSkipExcluded']++
|
||||
}
|
||||
if (($GPO.Enabled -eq $false -or $GPO.Empty -eq $true -or $GPO.Linked -eq $false -or $GPO.ApplyPermission -eq $false) -and $GPO.Exclude -eq $true) {
|
||||
$Script:Reporting['GPOList']['Variables']['GPONotValidButExcluded']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPONotValidButSkippedOrExcluded']++
|
||||
} elseif (($GPO.Enabled -eq $false -or $GPO.Empty -eq $true -or $GPO.Linked -eq $false -or $GPO.ApplyPermission -eq $false) -and $GPO.Days -le $Script:Reporting['GPOList']['Variables']['GPOOlderThan']) {
|
||||
# Skip GPOS that are younger than 30 days
|
||||
$Script:Reporting['GPOList']['Variables']['GPONotValidButSkip']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPONotValidButSkippedOrExcluded']++
|
||||
}
|
||||
if (($GPO.Enabled -eq $false -or $GPO.Empty -eq $true -or $GPO.Linked -eq $false -or $GPO.ApplyPermission -eq $false) -and $GPO.Days) {
|
||||
$Script:Reporting['GPOList']['Variables']['GPONotValid']++
|
||||
$Script:Reporting['GPOList']['Variables']['GPONotValidPerDomain'][$GPO.DomainName]++
|
||||
} else {
|
||||
@@ -133,49 +149,55 @@
|
||||
}
|
||||
}
|
||||
$Script:Reporting['GPOList']['Variables']['GPOTotal'] = $Script:Reporting['GPOList']['Data'].Count
|
||||
if ($Script:Reporting['GPOList']['Variables']['GPONotValid'] -gt 0) {
|
||||
if ($Script:Reporting['GPOList']['Variables']['GPONotValid'] -gt 0 -and $Script:Reporting['GPOList']['Variables']['GPONotValidButSkippedOrExcluded'] -ne $Script:Reporting['GPOList']['Variables']['GPONotValid']) {
|
||||
$Script:Reporting['GPOList']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPOList']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = @{
|
||||
GPONotValidPerDomain = $null
|
||||
GPOValidPerDomain = $null
|
||||
GPONotOptimizedPerDomain = $null
|
||||
GPOOptimizedPerDomain = $null
|
||||
GPOProblemPerDomain = $null
|
||||
GPONoProblemPerDomain = $null
|
||||
GPOApplyPermissionYesPerDomain = $null
|
||||
GPOApplyPermissionNoPerDomain = $null
|
||||
GPOWithProblems = 0
|
||||
ComputerOptimizedYes = 0
|
||||
ComputerOptimizedNo = 0
|
||||
ComputerProblemYes = 0
|
||||
ComputerProblemNo = 0
|
||||
UserOptimizedYes = 0
|
||||
UserOptimizedNo = 0
|
||||
UserProblemYes = 0
|
||||
UserProblemNo = 0
|
||||
GPOOptimized = 0
|
||||
GPONotOptimized = 0
|
||||
GPOProblem = 0
|
||||
GPONoProblem = 0
|
||||
GPONotLinked = 0
|
||||
GPOLinked = 0
|
||||
GPOEmpty = 0
|
||||
GPONotEmpty = 0
|
||||
GPOEmptyAndUnlinked = 0
|
||||
GPOEmptyOrUnlinked = 0
|
||||
GPOLinkedButEmpty = 0
|
||||
GPOEnabled = 0
|
||||
GPODisabled = 0
|
||||
GPOValid = 0
|
||||
GPONotValid = 0
|
||||
GPOLinkedButLinkDisabled = 0
|
||||
GPOTotal = 0
|
||||
ApplyPermissionYes = 0
|
||||
ApplyPermissionNo = 0
|
||||
GPOOlderThan = 30
|
||||
GPONotValidPerDomain = $null
|
||||
GPOValidPerDomain = $null
|
||||
GPONotOptimizedPerDomain = $null
|
||||
GPOOptimizedPerDomain = $null
|
||||
GPOProblemPerDomain = $null
|
||||
GPONoProblemPerDomain = $null
|
||||
GPOApplyPermissionYesPerDomain = $null
|
||||
GPOApplyPermissionNoPerDomain = $null
|
||||
GPOWithProblems = 0
|
||||
ComputerOptimizedYes = 0
|
||||
ComputerOptimizedNo = 0
|
||||
ComputerProblemYes = 0
|
||||
ComputerProblemNo = 0
|
||||
UserOptimizedYes = 0
|
||||
UserOptimizedNo = 0
|
||||
UserProblemYes = 0
|
||||
UserProblemNo = 0
|
||||
GPOOptimized = 0
|
||||
GPONotOptimized = 0
|
||||
GPOProblem = 0
|
||||
GPONoProblem = 0
|
||||
GPONotLinked = 0
|
||||
GPOLinked = 0
|
||||
GPOEmpty = 0
|
||||
GPONotEmpty = 0
|
||||
GPOEmptyAndUnlinked = 0
|
||||
GPOEmptyOrUnlinked = 0
|
||||
GPOLinkedButEmpty = 0
|
||||
GPOEnabled = 0
|
||||
GPODisabled = 0
|
||||
GPOSkip = 0
|
||||
GPOSkipExcluded = 0
|
||||
GPOValid = 0
|
||||
GPONotValid = 0
|
||||
GPONotValidButSkip = 0
|
||||
GPONotValidButExcluded = 0
|
||||
GPONotValidButSkippedOrExcluded = 0
|
||||
GPOLinkedButLinkDisabled = 0
|
||||
GPOTotal = 0
|
||||
ApplyPermissionYes = 0
|
||||
ApplyPermissionNo = 0
|
||||
}
|
||||
Overview = {
|
||||
|
||||
@@ -191,7 +213,8 @@
|
||||
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']['GPONotValid'] -FontWeight normal, bold {
|
||||
New-HTMLListItem -Text "Group Policies exclusions defined: ", $Script:Reporting['GPOList']['Variables']['GPOSkipExcluded'] -FontWeight normal, bold -Color None, DeepSkyBlue
|
||||
New-HTMLListItem -Text "Group Policies ", "NOT", " valid: ", $Script:Reporting['GPOList']['Variables']['GPONotValid'] -FontWeight normal, bold, 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
|
||||
@@ -200,7 +223,14 @@
|
||||
New-HTMLListItem -Text "Group Policies that are disabled (both user/computer sections): ", $Script:Reporting['GPOList']['Variables']['GPODisabled'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies that have no Apply Permission: ", $Script:Reporting['GPOList']['Variables']['ApplyPermissionNo'] -FontWeight normal, bold
|
||||
}
|
||||
}
|
||||
} -Color Black, Red, Black, Red, Black
|
||||
New-HTMLListItem -Text @(
|
||||
"Group Policies ", "NOT", " valid, to skip (because of age): ", $Script:Reporting['GPOList']['Variables']['GPONotValidButSkip'], " (modified less than $($Script:Reporting['GPOList']['Variables']['GPOOlderThan']) days ago)"
|
||||
) -FontWeight 'normal', 'bold', 'normal', 'bold', 'normal' -Color 'Black', 'Red', 'Black', 'Red', 'Black'
|
||||
New-HTMLListItem -Text @(
|
||||
"Group Policies ", "NOT", " valid, to skip (because of exclusions): ", $Script:Reporting['GPOList']['Variables']['GPONotValidButExcluded']
|
||||
) -FontWeight 'normal', 'bold', 'normal', 'bold', 'normal' -Color 'Black', 'Red', 'Black', 'Red', 'Black'
|
||||
New-HTMLListItem -Text "Group Policies recently modified: ", $Script:Reporting['GPOList']['Variables']['GPOSkip'], " (modified less than $($Script:Reporting['GPOList']['Variables']['GPOOlderThan']) days ago)" -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
@@ -276,6 +306,29 @@
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOList']['Variables']['GPONotOptimizedPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
# Just in case report is too big and the full file is not attached
|
||||
New-HTMLText -FontSize 10pt -Text "To generate up to date report please execute: " -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Install-Module GPOZaurr -Force', ' or ', ' install module manually.' -Color RoyalBlue, None, None
|
||||
New-HTMLListItem -Text 'Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrGPOPListBefore.html -Verbose -Type GPOList' -Color RoyalBlue
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text 'Steps above will generate above summary with more details allowing you to get up to date report and steps on how to fix it.'
|
||||
|
||||
if ($Script:Reporting['GPOList']['Exclusions']) {
|
||||
New-HTMLText -LineBreak
|
||||
New-HTMLText -Text @(
|
||||
"While preparing this report following exclusions were defined. "
|
||||
"Please make sure that when you execute your steps to include those exclusions to prevent any issues. "
|
||||
) -FontSize 10pt -FontWeight bold, normal -Color Red, None -LineBreak
|
||||
|
||||
New-HTMLText -Text "Code to use for exclusions: " -FontSize 10pt -FontWeight bold -LineBreak
|
||||
|
||||
$Code = New-GPOZaurrExclusions -ExclusionsArray $Script:Reporting['GPOList']['Exclusions']
|
||||
|
||||
if ($Code) {
|
||||
New-HTMLCodeBlock -Code $Code -Style powershell
|
||||
}
|
||||
}
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
@@ -352,6 +405,18 @@
|
||||
} -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."
|
||||
}
|
||||
if ($Script:Reporting['GPOList']['Exclusions']) {
|
||||
New-HTMLWizardStep -Name 'Required exclusions' {
|
||||
New-HTMLText -Text @(
|
||||
"While preparing this report following exclusions were defined. "
|
||||
"Please make sure that when you execute your steps to include those exclusions to prevent any issues. "
|
||||
)
|
||||
$Code = New-GPOZaurrExclusions -ExclusionsArray $Script:Reporting['GPOList']['Exclusions']
|
||||
if ($Code) {
|
||||
New-HTMLCodeBlock -Code $Code -Style powershell
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
@@ -392,11 +457,14 @@
|
||||
"You would do so using following approach "
|
||||
) -FontSize 10pt -FontWeight bold, normal
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Empty, Unlinked, Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor' {
|
||||
$Exclusions = {
|
||||
Skip-GroupPolicy -Name 'TEST | Drive Mapping'
|
||||
Skip-GroupPolicy -Name 'Default Domain Policy'
|
||||
Skip-GroupPolicy -Name 'Default Domain Controllers Policy' -DomaiName 'JustOneDomain'
|
||||
} -WhatIf
|
||||
'{D39BF08A-87BF-4662-BFA0-E56240EBD5A2}'
|
||||
'COMPUTERS | Enable Sets'
|
||||
}
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Empty, Unlinked, Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor' -WhatIf -ExcludeGroupPolicies $Exclusions
|
||||
}
|
||||
New-HTMLText -Text @(
|
||||
"Code above when executed will scan YourDomainYouHavePermissionsFor, find all empty, unlinked, disabled group policies, backup any GPO just before it's to be deleted to `$Env:UserProfile\Desktop\GPO. "
|
||||
@@ -405,6 +473,13 @@
|
||||
"Now go ahead and find what's there"
|
||||
)
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Remove GPOs (Manual)' {
|
||||
New-HTMLText -Text @(
|
||||
"Please condider deleting GPOs manually if the amount of GPOs to delete is small enough. "
|
||||
"Deleting 1-5-30 GPOs manually on domain of 4000 GPOs will be much faster than doing it in controlled manner with automated steps mentioned on next steps. "
|
||||
"What can take 30 minutes manually, can take 8 hours using automated script, because of amount of checks required by the script over and over to delete a single GPO. "
|
||||
) -FontWeight normal, bold, normal, bold, normal, bold, normal, normal -Color Black, Red, Black, Red, Black
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Remove GPOs that are EMPTY' {
|
||||
New-HTMLText -Text @(
|
||||
"Following command when executed removes every ",
|
||||
@@ -416,26 +491,26 @@
|
||||
"You can skip parameters related to backup if you did backup all GPOs prior to running remove command. "
|
||||
) -FontWeight normal, bold, normal, bold, normal, bold, normal, normal -Color Black, Red, Black, Red, Black
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Empty -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Empty -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Empty -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Empty -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be deleted matches expected data. "
|
||||
} -LineBreak
|
||||
New-HTMLText -Text "Once happy with results please follow with command (this will start fixing process): " -LineBreak -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Empty -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Empty -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Empty -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Empty -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed deletes only first X empty GPOs. Use LimitProcessing parameter to prevent mass delete and increase the counter when no errors occur."
|
||||
@@ -455,26 +530,26 @@
|
||||
"You can skip parameters related to backup if you did backup all GPOs prior to running remove command. "
|
||||
) -FontWeight normal, bold, normal, bold, normal, bold, normal, normal -Color Black, Red, Black, Red, Black
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be deleted matches expected data. "
|
||||
} -LineBreak
|
||||
New-HTMLText -Text "Once happy with results please follow with command (this will start fixing process): " -LineBreak -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Unlinked -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed deletes only first X unlinked GPOs. Use LimitProcessing parameter to prevent mass delete and increase the counter when no errors occur."
|
||||
@@ -497,26 +572,26 @@
|
||||
""
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be deleted matches expected data. "
|
||||
} -LineBreak
|
||||
New-HTMLText -Text "Once happy with results please follow with command (this will start fixing process): " -LineBreak -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
Remove-GPOZaurr -RequireDays 30 -Type Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed deletes only first X disabled GPOs. Use LimitProcessing parameter to prevent mass delete and increase the counter when no errors occur. "
|
||||
@@ -539,26 +614,26 @@
|
||||
""
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type NoApplyPermission -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf
|
||||
Remove-GPOZaurr -RequireDays 30 -Type NoApplyPermission -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type NoApplyPermission -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
Remove-GPOZaurr -RequireDays 30 -Type NoApplyPermission -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be deleted matches expected data. "
|
||||
} -LineBreak
|
||||
New-HTMLText -Text "Once happy with results please follow with command (this will start fixing process): " -LineBreak -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type NoApplyPermission -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose
|
||||
Remove-GPOZaurr -RequireDays 30 -Type NoApplyPermission -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurr -Type NoApplyPermission -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
Remove-GPOZaurr -RequireDays 30 -Type NoApplyPermission -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed deletes only first X NoApplyPermission GPOs. Use LimitProcessing parameter to prevent mass delete and increase the counter when no errors occur. "
|
||||
@@ -612,10 +687,11 @@
|
||||
}
|
||||
New-HTMLText -Text "If there are no more problems to solve, GPOs to optimize in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
<#
|
||||
if ($Script:Reporting['GPOList']['Exclusions']) {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLSection -Name 'Group Policies Exclusions' {
|
||||
@@ -626,11 +702,12 @@
|
||||
New-HTMLSection -Name 'Group Policies Exclusions Code' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLText -Text 'Please make sure to use following exclusions when executing removal' -FontSize 10pt
|
||||
New-HTMLCodeBlock -Code $Script:Reporting['GPOList']['ExclusionsCode']
|
||||
New-HTMLCodeBlock -Code $Script:Reporting['GPOList']['Exclusions']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#>
|
||||
}
|
||||
if ($Script:Reporting['GPOList']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Errors to Review' {
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
}
|
||||
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
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,97 +125,6 @@
|
||||
New-HTMLText -Text "Please review output in table and follow the steps below table to get NetLogon permissions in order." -FontSize 10pt
|
||||
}
|
||||
Solution = {
|
||||
# New-HTMLTab -Name 'NetLogon Owners' {
|
||||
# New-HTMLSection -Invisible {
|
||||
# New-HTMLPanel {
|
||||
# & $Script:GPOConfiguration['NetLogonPermissions']['Summary']
|
||||
# }
|
||||
# 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 File Owners' {
|
||||
# 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
|
||||
# New-HTMLTableCondition -Name 'Status' -Value "OK" -BackgroundColor LightGreen -ComparisonType string -Operator eq
|
||||
# New-HTMLTableCondition -Name 'Status' -Value "OK" -BackgroundColor Salmon -ComparisonType string -Operator ne
|
||||
# }
|
||||
# }
|
||||
# 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 -OwnerOnly -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
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# 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-HTMLTab -Name 'NetLogon Permissions' {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
& $Script:GPOConfiguration['NetLogonPermissions']['Summary']
|
||||
@@ -272,6 +181,7 @@
|
||||
New-HTMLText -Text @(
|
||||
"In case of NETLOGON permissions it's impossible to tell what in a given moment for given domain should be automatically removed except for the very obvious ",
|
||||
"unknown ", 'permissions. Domain Admins have to make their assesment on and remove permissions from users or groups that '
|
||||
"they think do not belong. "
|
||||
) -FontWeight normal, bold, normal
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Verification report' {
|
||||
@@ -283,7 +193,7 @@
|
||||
}
|
||||
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
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
$GPOZaurrOrganizationalUnit = [ordered] @{
|
||||
Name = 'Group Policy Organizational Units'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
if ($Script:Reporting['GPOOrganizationalUnit']['Exclusions']) {
|
||||
Get-GPOZaurrOrganizationalUnit -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExcludeOrganizationalUnit $Script:Reporting['GPOOrganizationalUnit']['Exclusions']
|
||||
} else {
|
||||
Get-GPOZaurrOrganizationalUnit -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
}
|
||||
}
|
||||
Processing = {
|
||||
# Create Per Domain Variables
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['RequiresDiffFixPerDomain'] = @{}
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'] = @{}
|
||||
foreach ($OU in $Script:Reporting['GPOOrganizationalUnit']['Data']) {
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['TotalOU']++
|
||||
# Create Per Domain Variables
|
||||
if (-not $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$OU.DomainName]) {
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$OU.DomainName] = 0
|
||||
}
|
||||
if ($OU.Status -contains 'Unlink GPO' -and $OU.Status -contains 'Delete OU') {
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPOEmpty']++
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFix']++
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$OU.DomainName]++
|
||||
} elseif ($OU.Status -contains 'Unlink GPO') {
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPO']++
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFix']++
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$OU.DomainName]++
|
||||
} elseif ($OU.Status -contains 'Delete OU') {
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['DeleteOU']++
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFix']++
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$OU.DomainName]++
|
||||
} elseif ($OU.Status -contains 'Excluded') {
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['Excluded']++
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['ExcludedOU'].Add($OU.Organizationalunit)
|
||||
} else {
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['Legitimate']++
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFix'] -gt 0) {
|
||||
$Script:Reporting['GPOOrganizationalUnit']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPOOrganizationalUnit']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = @{
|
||||
TotalOU = 0
|
||||
UnlinkGPO = 0
|
||||
UnlinkGPOEmpty = 0
|
||||
DeleteOU = 0
|
||||
Legitimate = 0
|
||||
Excluded = 0
|
||||
ExcludedOU = [System.Collections.Generic.List[string]]::new()
|
||||
WillFix = 0
|
||||
WillFixPerDomain = $null
|
||||
}
|
||||
Overview = {
|
||||
|
||||
}
|
||||
Summary = {
|
||||
New-HTMLText -FontSize 10pt -Text @(
|
||||
"In most Active Directories there are a lot of Organizational Units that have different use cases to store different type of objects. "
|
||||
"As Active Directories change over time you can often find Organizational Units with linked GPOs and no objects inside. "
|
||||
"In some cases thats's expected, but in some cases it's totally unnessecary, and for very large AD can be a problem. "
|
||||
"Additionally only User and Computer objects can have GPO applied to them, so having GPO applied to a any other object type won't really work. "
|
||||
)
|
||||
New-HTMLText -FontSize 10pt -Text "Following can happen: " -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Organizational Units that can have Group Policies unlinked (objects exists): ', $Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPO'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Organizational Units that can have Group Policies unlinked (no applicable objects): ', $Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPOEmpty'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Organizational Units that can be deleted (no objects/no gpos): ", $Script:Reporting['GPOOrganizationalUnit']['Variables']['DeleteOU'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOOrganizationalUnit']['Variables']['WillFixPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
|
||||
if ($Script:Reporting['GPOOrganizationalUnit']['Variables']['ExcludedOU'].Count -gt 0) {
|
||||
New-HTMLText -Text @(
|
||||
'There are ',
|
||||
$Script:Reporting['GPOOrganizationalUnit']['Variables']['ExcludedOU'].Count,
|
||||
" Organizational Units that are excluded.",
|
||||
" Please make sure to exclude those when executing unlinking/removal procedures. "
|
||||
) -FontSize 10pt -FontWeight normal, bold, normal, bold -Color None, Red, None, Red
|
||||
<#
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($OU in $Script:Reporting['GPOOrganizationalUnit']['Variables']['ExcludedOU']) {
|
||||
New-HTMLListItem -Text $OU -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
#>
|
||||
}
|
||||
|
||||
New-HTMLText -Text @(
|
||||
"Please make sure that you really want to unlink GPO or delete Organizational Unit before executing changes. Sometimes it's completly valid to keep one or the other. "
|
||||
"Unlinking GPO from OU that has no Computer or User objects is fairly safe exercise. Removing OU requires a bit more dive in, and should only be executed if you know what you're doing. "
|
||||
) -FontWeight normal, bold -Color None, Red -FontSize 10pt
|
||||
|
||||
if ($Script:Reporting['GPOOrganizationalUnit']['Exclusions']) {
|
||||
New-HTMLText -LineBreak
|
||||
New-HTMLText -Text @(
|
||||
"While preparing this report following exclusions were defined. "
|
||||
"Please make sure that when you execute your steps to include those exclusions to prevent any issues. "
|
||||
) -FontSize 10pt -FontWeight bold, normal -Color Red, None -LineBreak
|
||||
|
||||
New-HTMLText -Text "Code to use for exclusions: " -FontSize 10pt -FontWeight bold -LineBreak
|
||||
|
||||
$Code = New-GPOZaurrExclusions -ExclusionsArray $Script:Reporting['GPOOrganizationalUnit']['Exclusions']
|
||||
|
||||
if ($Code) {
|
||||
New-HTMLCodeBlock -Code $Code -Style powershell
|
||||
}
|
||||
}
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
& $Script:GPOConfiguration['GPOOrganizationalUnit']['Summary']
|
||||
}
|
||||
New-HTMLPanel {
|
||||
New-HTMLChart {
|
||||
New-ChartBarOptions -Type bar -Distributed
|
||||
New-ChartAxisY -LabelMaxWidth 200 -LabelAlign left -Show
|
||||
New-ChartBar -Name "Unlink GPO ($($Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPO']))" -Value $Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPO']
|
||||
New-ChartBar -Name "Unlink GPO Delete OU ($($Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPOEmpty']))" -Value $Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPOEmpty']
|
||||
New-ChartBar -Name "Delete OU ($($Script:Reporting['GPOOrganizationalUnit']['Variables']['DeleteOU']))" -Value $Script:Reporting['GPOOrganizationalUnit']['Variables']['DeleteOU']
|
||||
} -Title 'Organizational Units' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policy Organizational Units' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOOrganizationalUnit']['Data'] -Filtering {
|
||||
New-TableHeader -ResponsiveOperations none -Names 'GPONames', 'Objects'
|
||||
New-HTMLTableCondition -Name 'Status' -ComparisonType string -Value 'Unlink GPO, Delete OU' -BackgroundColor Salmon -Row
|
||||
New-HTMLTableCondition -Name 'Status' -ComparisonType string -Value 'Unlink GPO' -BackgroundColor YellowOrange -Row
|
||||
New-HTMLTableCondition -Name 'Status' -ComparisonType string -Value 'Delete OU' -BackgroundColor Red -Row
|
||||
New-HTMLTableCondition -Name 'Status' -ComparisonType string -Value 'OK' -BackgroundColor LightGreen -Row
|
||||
New-HTMLTableCondition -Name 'Status' -ComparisonType string -Value 'Excluded' -BackgroundColor DeepSkyBlue -Row
|
||||
} -PagingOptions 10, 20, 30, 40, 50 -ExcludeProperty GPO
|
||||
}
|
||||
if ($Script:Reporting['Settings']['HideSteps'] -eq $false) {
|
||||
New-HTMLSection -Name 'Steps to fix Group Organizational Units' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
#New-HTMLText -Text 'Following steps will guide you how to fix group policy owners'
|
||||
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."
|
||||
}
|
||||
if ($Script:Reporting['GPOOrganizationalUnit']['Exclusions']) {
|
||||
New-HTMLWizardStep -Name 'Required exclusions' {
|
||||
New-HTMLText -Text @(
|
||||
"While preparing this report following exclusions were defined. "
|
||||
"Please make sure that when you execute your steps to include those exclusions to prevent any issues. "
|
||||
)
|
||||
$Code = New-GPOZaurrExclusions -ExclusionsArray $Script:Reporting['GPOOrganizationalUnit']['Exclusions']
|
||||
|
||||
if ($Code) {
|
||||
New-HTMLCodeBlock -Code $Code -Style powershell
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Prepare report' {
|
||||
New-HTMLText -Text "Depending when this report was run you may want to prepare new report before proceeding with unlinking unused Group Policies. To generate new report please use:"
|
||||
New-HTMLCodeBlock -Code {
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrGPOOrganizationalUnitBefore.html -Verbose -Type GPOOrganizationalUnit
|
||||
}
|
||||
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 {
|
||||
$OwnersGPO = Get-GPOZaurrOrganizationalUnit -Verbose
|
||||
$OwnersGPO | Format-Table
|
||||
}
|
||||
New-HTMLText -Text "It provides same data as you see in table above just doesn't prettify it for you."
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Unlink unused Group Policies' {
|
||||
New-HTMLText -Text @(
|
||||
"Following command when executed runs cleanup procedure that unlinks all Group Policies from Organizational Units that have no user or computer objects. "
|
||||
"Make sure when running it for the first time to run it with ",
|
||||
"WhatIf",
|
||||
" parameter as shown below to prevent accidental unlinking."
|
||||
'When run it will remove any GPO links from Organizational Units that have no objects applicable for GPOs.'
|
||||
) -FontWeight normal, normal, bold, normal -Color Black, Black, Red, Black
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrLinkEmptyOU -WhatIf -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrLinkEmptyOU -WhatIf -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be removed matches expected data. "
|
||||
"Keep in mind that there is no backup for this, and if link is removed you would need to relink it yourself."
|
||||
"Once you remove it, it's gone. "
|
||||
} -LineBreak
|
||||
New-HTMLText -Text 'Once happy with results please follow with command (this will start removal process): ' -LineBreak -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrLinkEmptyOU -WhatIf -LimitProcessing 2 -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrLinkEmptyOU -WhatIf -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
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. "
|
||||
} -LineBreak
|
||||
New-HTMLText -TextBlock {
|
||||
"It's possible to exclude certain OU's from having GPO's unlinked using follwing method: "
|
||||
} -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
$Exclude = @(
|
||||
"OU=Groups,OU=Production,DC=ad,DC=evotec,DC=pl"
|
||||
"OU=Test \, OU,OU=ITR02,DC=ad,DC=evotec,DC=xyz"
|
||||
)
|
||||
Remove-GPOZaurrLinkEmptyOU -Verbose -LimitProcessing 3 -WhatIf -ExcludeOrganizationalUnit $Exclude
|
||||
}
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Delete unused Organizational Units' {
|
||||
New-HTMLText -Text @(
|
||||
"Following automation is not yet implemented. Requires more testing as potentially it could do more damage than help."
|
||||
)
|
||||
}
|
||||
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\GPOZaurrGPOOrganizationalUnitAfter.html -Verbose -Type GPOOrganizationalUnit
|
||||
}
|
||||
New-HTMLText -Text "If everything is healthy in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOOrganizationalUnit']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOOrganizationalUnit']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
$GPOZaurrOrphans = [ordered] @{
|
||||
Name = 'Orphaned Group Policies'
|
||||
Name = 'Broken Group Policies'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
@@ -7,41 +7,52 @@
|
||||
Get-GPOZaurrBroken -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
}
|
||||
Processing = {
|
||||
$Script:Reporting['GPOOrphans']['Variables']['ToBeDeletedPerDomain'] = @{}
|
||||
$Script:Reporting['GPOOrphans']['Variables']['NotAvailablePermissionIssuePerDomain'] = @{}
|
||||
foreach ($GPO in $Script:Reporting['GPOOrphans']['Data']) {
|
||||
if (-not $Script:Reporting['GPOOrphans']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOOrphans']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName] = 0
|
||||
$Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'] = @{}
|
||||
$Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssuePerDomain'] = @{}
|
||||
$Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssuePerDomain'] = @{}
|
||||
foreach ($GPO in $Script:Reporting['GPOBroken']['Data']) {
|
||||
if (-not $Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOOrphans']['Variables']['NotAvailablePermissionIssuePerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOOrphans']['Variables']['NotAvailablePermissionIssuePerDomain'][$GPO.DomainName] = 0
|
||||
if (-not $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssuePerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssuePerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssuePerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssuePerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if ($GPO.Status -eq 'Not available in AD') {
|
||||
$Script:Reporting['GPOOrphans']['Variables']['NotAvailableInAD']++
|
||||
$Script:Reporting['GPOOrphans']['Variables']['ToBeDeleted']++
|
||||
$Script:Reporting['GPOOrphans']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]++
|
||||
$Script:Reporting['GPOBroken']['Variables']['NotAvailableInAD']++
|
||||
$Script:Reporting['GPOBroken']['Variables']['ToBeDeleted']++
|
||||
$Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]++
|
||||
} elseif ($GPO.Status -eq 'Not available on SYSVOL') {
|
||||
$Script:Reporting['GPOOrphans']['Variables']['NotAvailableOnSysvol']++
|
||||
$Script:Reporting['GPOOrphans']['Variables']['ToBeDeleted']++
|
||||
$Script:Reporting['GPOOrphans']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]++
|
||||
$Script:Reporting['GPOBroken']['Variables']['NotAvailableOnSysvol']++
|
||||
$Script:Reporting['GPOBroken']['Variables']['ToBeDeleted']++
|
||||
$Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]++
|
||||
} elseif ($GPO.Status -eq 'Permissions issue') {
|
||||
$Script:Reporting['GPOOrphans']['Variables']['NotAvailablePermissionIssue']++
|
||||
$Script:Reporting['GPOOrphans']['Variables']['NotAvailablePermissionIssuePerDomain'][$GPO.DomainName]++
|
||||
$Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue']++
|
||||
$Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssuePerDomain'][$GPO.DomainName]++
|
||||
} elseif ($GPO.Status -eq 'ObjectClass issue') {
|
||||
$Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssue']++
|
||||
$Script:Reporting['GPOBroken']['Variables']['ToBeDeleted']++
|
||||
$Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssuePerDomain'][$GPO.DomainName]++
|
||||
$Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$GPO.DomainName]++
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOOrphans']['Variables']['ToBeDeleted'] -gt 0) {
|
||||
$Script:Reporting['GPOOrphans']['ActionRequired'] = $true
|
||||
if ($Script:Reporting['GPOBroken']['Variables']['ToBeDeleted'] -gt 0) {
|
||||
$Script:Reporting['GPOBroken']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPOOrphans']['ActionRequired'] = $false
|
||||
$Script:Reporting['GPOBroken']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = @{
|
||||
NotAvailableInAD = 0
|
||||
NotAvailableOnSysvol = 0
|
||||
NotAvailablePermissionIssue = 0
|
||||
NotAvailablePermissionIssuePerDomain = $null
|
||||
ToBeDeleted = 0
|
||||
ToBeDeletedPerDomain = $null
|
||||
NotAvailableInAD = 0
|
||||
NotAvailableOnSysvol = 0
|
||||
NotAvailablePermissionIssue = 0
|
||||
NotAvailablePermissionIssuePerDomain = $null
|
||||
ToBeDeleted = 0
|
||||
ToBeDeletedPerDomain = $null
|
||||
NotAvailableObjectClassIssue = 0
|
||||
NotAvailableObjectClassIssuePerDomain = $null
|
||||
}
|
||||
Overview = {
|
||||
<#
|
||||
@@ -58,15 +69,15 @@
|
||||
}
|
||||
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
|
||||
New-HTMLListItem -Text 'Group Policies on SYSVOL, but no details in AD: ', $Script:Reporting['GPOBroken']['Variables']['NotAvailableInAD'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Group Policies in AD, but no content on SYSVOL: ', $Script:Reporting['GPOBroken']['Variables']['NotAvailableOnSysvol'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which couldn't be assed due to permissions issue: ", $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text 'Those problems must be resolved before doing other clenaup activities.'
|
||||
New-HTMLChart {
|
||||
New-ChartBarOptions -Type barStacked
|
||||
New-ChartLegend -Name 'Not in AD', 'Not on SYSVOL', 'Permissions Issue' -Color Crimson, LightCoral, IndianRed
|
||||
New-ChartBar -Name 'Orphans' -Value $Script:Reporting['GPOOrphans']['Variables']['NotAvailableInAD'], $Script:Reporting['GPOOrphans']['Variables']['NotAvailableOnSysvol'], $Script:Reporting['GPOOrphans']['Variables']['NotAvailablePermissionIssue']
|
||||
New-ChartBar -Name 'Orphans' -Value $Script:Reporting['GPOBroken']['Variables']['NotAvailableInAD'], $Script:Reporting['GPOBroken']['Variables']['NotAvailableOnSysvol'], $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue']
|
||||
} -Title 'Broken / Orphaned Group Policies' -TitleAlignment center
|
||||
}
|
||||
#>
|
||||
@@ -85,14 +96,15 @@
|
||||
} -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
|
||||
New-HTMLListItem -Text 'Group Policies on SYSVOL, but no details in AD: ', $Script:Reporting['GPOBroken']['Variables']['NotAvailableInAD'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Group Policies in AD, but no content on SYSVOL: ', $Script:Reporting['GPOBroken']['Variables']['NotAvailableOnSysvol'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text 'Group Policies which exists, but have wrong ObjectClass: ', $Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssue'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which couldn't be assessed due to permissions issue: ", $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOOrphans']['Variables']['ToBeDeletedPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOOrphans']['Variables']['ToBeDeletedPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
foreach ($Domain in $Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOBroken']['Variables']['ToBeDeletedPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text "Please review output in table and follow the steps below table to get Active Directory Group Policies in healthy state." -FontSize 10pt
|
||||
@@ -100,25 +112,26 @@
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
& $Script:GPOConfiguration['GPOOrphans']['Summary']
|
||||
& $Script:GPOConfiguration['GPOBroken']['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']
|
||||
New-ChartLegend -Name 'Not in AD', 'Not on SYSVOL', 'ObjectClass Issue', 'Permissions Issue' -Color Crimson, LightCoral, MediumOrchid, IndianRed
|
||||
New-ChartBar -Name 'Broken' -Value $Script:Reporting['GPOBroken']['Variables']['NotAvailableInAD'], $Script:Reporting['GPOBroken']['Variables']['NotAvailableOnSysvol'], $Script:Reporting['GPOBroken']['Variables']['NotAvailableObjectClassIssue'], $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue']
|
||||
} -Title 'Broken / Orphaned Group Policies' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Health State of Group Policies' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOOrphans']['Data'] -Filtering {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOBroken']['Data'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Status' -Value "Not available in AD" -BackgroundColor Salmon -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'Status' -Value "Not available on SYSVOL" -BackgroundColor LightCoral -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'Status' -Value "ObjectClass issue" -BackgroundColor MediumOrchid -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'Status' -Value "Permissions issue" -BackgroundColor MediumVioletRed -ComparisonType string -Color White
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
if ($Script:Reporting['Settings']['HideSteps'] -eq $false) {
|
||||
New-HTMLSection -Name 'Steps to fix - Not available on SYSVOL / Active Directory' {
|
||||
New-HTMLSection -Name 'Steps to fix - Not available on SYSVOL / Active Directory / ObjectClass issue' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLWizard {
|
||||
@@ -133,7 +146,7 @@
|
||||
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
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrBrokenGpoBefore.html -Verbose -Type GPOBroken
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"When executed it will take a while to generate all data and provide you with new report depending on size of environment."
|
||||
@@ -243,23 +256,61 @@
|
||||
"If there's nothing else to be deleted on AD side, we can skip to next step step. "
|
||||
}
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Fix GPOs of wrong ObjectClass' {
|
||||
New-HTMLText -Text @(
|
||||
"Following command when executed runs cleanup procedure that removes all GPOs which have ObjectClass of Container, rather than required groupPolicyContainer. "
|
||||
"Make sure when running it for the first time to run it with ",
|
||||
"WhatIf",
|
||||
" parameter as shown below to prevent accidental removal."
|
||||
'When run it will remove GPO metadata from AD, and any files/folders from SYSVOL.'
|
||||
) -FontWeight normal, normal, bold, normal -Color Black, Black, Red, Black
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrBroken -Type ObjectClass -WhatIf -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrBroken -Type ObjectClass -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor' -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be deleted matches expected data. "
|
||||
"Keep in mind that there is no backup for this as backup process doesn't see GPOs that are of wrong ObjectClass. "
|
||||
"Once you delete it, it's gone. "
|
||||
} -LineBreak
|
||||
New-HTMLText -Text 'Once happy with results please follow with command (this will start deletion process): ' -LineBreak -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrBroken -Type ObjectClass -LimitProcessing 2 -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrBroken -Type ObjectClass -LimitProcessing 2 -IncludeDomains 'YourDomainYouHavePermissionsFor' -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed deletes only first X broken GPOs. Use LimitProcessing parameter to prevent mass delete and increase the counter when no errors occur. "
|
||||
"Repeat step above as much as needed increasing LimitProcessing count till there's nothing left. In case of any issues please review and action accordingly. "
|
||||
"If there's nothing else to be deleted, we can skip to next step step. "
|
||||
}
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Verification report' {
|
||||
New-HTMLText -TextBlock {
|
||||
"Once cleanup task was executed properly, we need to verify that report now shows no problems."
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrBrokenGpoAfter.html -Verbose -Type GPOOrphans
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrBrokenGpoAfter.html -Verbose -Type GPOBroken
|
||||
}
|
||||
New-HTMLText -Text "If everything is healthy in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOOrphans']['WarningsAndErrors']) {
|
||||
if ($Script:Reporting['GPOBroken']['WarningsAndErrors']) {
|
||||
New-HTMLSection -Name 'Warnings & Errors to Review' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOOrphans']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOBroken']['WarningsAndErrors'] -Filtering {
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Warning' -BackgroundColor SandyBrown -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Type' -Value 'Error' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
}
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrOwner -IncludeSysvol -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
if ($Script:Reporting['GPOOwners']['Exclusions']) {
|
||||
Get-GPOZaurrOwner -IncludeSysvol -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ApprovedOwner $Script:Reporting['GPOOwners']['Exclusions']
|
||||
} else {
|
||||
Get-GPOZaurrOwner -IncludeSysvol -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
}
|
||||
}
|
||||
Processing = {
|
||||
# Create Per Domain Variables
|
||||
@@ -19,17 +23,35 @@
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillFixPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
# Checks
|
||||
if ($GPO.IsOwnerConsistent) {
|
||||
if ($GPO.Status -contains 'Consistent') {
|
||||
$Script:Reporting['GPOOwners']['Variables']['IsConsistent']++
|
||||
} else {
|
||||
} elseif ($GPO.Status -contains 'Inconsistent') {
|
||||
$Script:Reporting['GPOOwners']['Variables']['IsNotConsistent']++
|
||||
}
|
||||
if ($GPO.IsOwnerAdministrative) {
|
||||
if ($GPO.Status -contains 'Administrative') {
|
||||
$Script:Reporting['GPOOwners']['Variables']['IsAdministrative']++
|
||||
} elseif ($GPO.Status -contains 'Approved') {
|
||||
$Script:Reporting['GPOOwners']['Variables']['IsApproved']++
|
||||
} else {
|
||||
$Script:Reporting['GPOOwners']['Variables']['IsNotAdministrative']++
|
||||
}
|
||||
if (($GPO.IsOwnerAdministrative -eq $false -or $GPO.IsOwnerConsistent -eq $false) -and $GPO.SysvolExists -eq $true) {
|
||||
|
||||
if ($GPO.SysvolExists -eq $false) {
|
||||
$Script:Reporting['GPOOwners']['Variables']['RequiresDiffFix']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['RequiresDiffFixPerDomain'][$GPO.DomainName]++
|
||||
} else {
|
||||
if ($GPO.Status -contains 'Inconsistent') {
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillFix']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillFixPerDomain'][$GPO.DomainName]++
|
||||
} elseif ($GPO.Status -contains 'NotAdministrative' -and $GPO.Status -notcontains 'Approved') {
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillFix']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillFixPerDomain'][$GPO.DomainName]++
|
||||
} else {
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillNotTouch']++
|
||||
}
|
||||
}
|
||||
<#
|
||||
if (($GPO.IsOwnerAdministrative -eq $false -or $GPO.IsOwnerConsistent -eq $false) -and $GPO.Status -and $GPO.SysvolExists -eq $true) {
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillFix']++
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillFixPerDomain'][$GPO.DomainName]++
|
||||
} elseif ($GPO.SysvolExists -eq $false) {
|
||||
@@ -38,6 +60,7 @@
|
||||
} else {
|
||||
$Script:Reporting['GPOOwners']['Variables']['WillNotTouch']++
|
||||
}
|
||||
#>
|
||||
}
|
||||
if ($Script:Reporting['GPOOwners']['Variables']['WillFix'] -gt 0) {
|
||||
$Script:Reporting['GPOOwners']['ActionRequired'] = $true
|
||||
@@ -47,6 +70,7 @@
|
||||
}
|
||||
Variables = @{
|
||||
IsAdministrative = 0
|
||||
IsApproved = 0
|
||||
IsNotAdministrative = 0
|
||||
IsConsistent = 0
|
||||
IsNotConsistent = 0
|
||||
@@ -77,21 +101,23 @@
|
||||
#>
|
||||
}
|
||||
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 -FontSize 10pt -Text @(
|
||||
"By default, GPO creation is usually maintained by Domain Admins or Enterprise Admins. "
|
||||
"When GPO is created by Domain Admins or Enterprise Admins group members, the GPO Owner is set to Domain Admins. "
|
||||
"When GPO is created by a 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 the relevant user. "
|
||||
"GPO Owners should be Domain Admins or Enterprise Admins to prevent abuse. "
|
||||
"If that isn't so, it means the owner can fully control GPO and potentially change its settings in an uncontrolled way. "
|
||||
"While at the moment of creation of new GPO, it's not a problem, in the long term, it's possible such a person may no longer be admin, yet keep their rights over GPO. "
|
||||
"As your 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 is 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, but approved Owners (for example AGPM): ', $Script:Reporting['GPOOwners']['Variables']['IsApproved'] -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
|
||||
@@ -114,6 +140,22 @@
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOOwners']['Variables']['RequiresDiffFixPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
|
||||
if ($Script:Reporting['GPOOwners']['Exclusions']) {
|
||||
New-HTMLText -LineBreak
|
||||
New-HTMLText -Text @(
|
||||
"While preparing this report following exclusions were defined. "
|
||||
"Please make sure that when you execute your steps to include those exclusions to prevent any issues. "
|
||||
) -FontSize 10pt -FontWeight bold, normal -Color Red, None -LineBreak
|
||||
|
||||
New-HTMLText -Text "Code to use for exclusions: " -FontSize 10pt -FontWeight bold -LineBreak
|
||||
|
||||
$Code = New-GPOZaurrExclusions -ExclusionsArray $Script:Reporting['GPOOwners']['Exclusions']
|
||||
|
||||
if ($Code) {
|
||||
New-HTMLCodeBlock -Code $Code -Style powershell
|
||||
}
|
||||
}
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
@@ -123,16 +165,25 @@
|
||||
New-HTMLPanel {
|
||||
New-HTMLChart {
|
||||
New-ChartBarOptions -Type barStacked
|
||||
New-ChartLegend -Name 'Yes', 'No' -Color LightGreen, Salmon
|
||||
New-ChartBar -Name 'Is administrative' -Value $Script:Reporting['GPOOwners']['Variables']['IsAdministrative'], $Script:Reporting['GPOOwners']['Variables']['IsNotAdministrative']
|
||||
New-ChartLegend -Name 'Yes', 'No', 'Approved' -Color LightGreen, Salmon, DeepSkyBlue
|
||||
New-ChartBar -Name 'Is administrative' -Value $Script:Reporting['GPOOwners']['Variables']['IsAdministrative'], $Script:Reporting['GPOOwners']['Variables']['IsNotAdministrative'], $Script:Reporting['GPOOwners']['Variables']['IsApproved']
|
||||
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: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
|
||||
#New-HTMLTableCondition -Name 'IsOwnerConsistent' -Value $false -BackgroundColor Salmon -ComparisonType string -Row
|
||||
#New-HTMLTableCondition -Name 'IsOwnerAdministrative' -Value $false -BackgroundColor Salmon -ComparisonType string -Row
|
||||
|
||||
New-HTMLTableCondition -Name 'Status' -Value 'Administrative, Consistent' -BackgroundColor LightGreen -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Status' -Value 'NotAdministrative, Consistent, Approved' -BackgroundColor DeepSkyBlue -ComparisonType string -Row
|
||||
|
||||
New-HTMLTableCondition -Name 'Status' -Value 'Administrative, Inconsistent' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
New-HTMLTableCondition -Name 'Status' -Value 'NotAdministrative, Inconsistent' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
#New-HTMLTableCondition -Name 'Status' -Value 'Administrative, Inconsistent, Approved' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
# New-HTMLTableCondition -Name 'Status' -Value 'NotAdministrative, Inconsistent, Approved' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
|
||||
} -PagingOptions 10, 20, 30, 40, 50
|
||||
}
|
||||
if ($Script:Reporting['Settings']['HideSteps'] -eq $false) {
|
||||
@@ -149,6 +200,19 @@
|
||||
} -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."
|
||||
}
|
||||
if ($Script:Reporting['GPOOwners']['Exclusions']) {
|
||||
New-HTMLWizardStep -Name 'Required exclusions' {
|
||||
New-HTMLText -Text @(
|
||||
"While preparing this report following exclusions were defined. "
|
||||
"Please make sure that when you execute your steps to include those exclusions to prevent any issues. "
|
||||
)
|
||||
$Code = New-GPOZaurrExclusions -ExclusionsArray $Script:Reporting['GPOOwners']['Exclusions']
|
||||
|
||||
if ($Code) {
|
||||
New-HTMLCodeBlock -Code $Code -Style powershell
|
||||
}
|
||||
}
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Prepare report' {
|
||||
New-HTMLText -Text "Depending when this report was run you may want to prepare new report before proceeding with fixing Group Policy Owners. To generate new report please use:"
|
||||
New-HTMLCodeBlock -Code {
|
||||
@@ -206,6 +270,22 @@
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed sets new owner only on first X non-compliant GPO Owners for AD/SYSVOL. Use LimitProcessing parameter to prevent mass change and increase the counter when no errors occur. "
|
||||
"Repeat step above as much as needed increasing LimitProcessing count till there's nothing left. In case of any issues please review and action accordingly. "
|
||||
} -LineBreak
|
||||
New-HTMLText -TextBlock {
|
||||
"It's possible to define certain owners as being approved (for example with domain that have AGPM). "
|
||||
"Make sure to verify if excluded/approved owners were provided in Required Exclusions tab, or add your own when nessecary. "
|
||||
"You can approve owners with following code: "
|
||||
} -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
$Approved = @(
|
||||
'EVOTEC\przemyslaw.klys'
|
||||
'EVOTEC\green.b'
|
||||
)
|
||||
Set-GPOZaurrOwner -Type All -Verbose -LimitProcessing 2 -ApprovedOwner $Approved
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Please keep in mind that ApprovedOwner is only applicable to Non-Administrative permissions to provide a way to approve special use cases. "
|
||||
"It won't do anything for inconsistent, unknown permissions as those are still treated as wrong. "
|
||||
}
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Verification report' {
|
||||
@@ -217,7 +297,7 @@
|
||||
}
|
||||
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
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
$GPOZaurrPermissions = [ordered] @{
|
||||
Name = 'Group Policy Permissions'
|
||||
Enabled = $true
|
||||
Action = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
Get-GPOZaurrPermission -Type All -IncludePermissionType GpoEditDeleteModifySecurity, GpoEdit, GpoCustom -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
Permissions = Get-GPOZaurrPermission -Type Administrative -IncludePermissionType GpoEditDeleteModifySecurity -ReturnSecurityWhenNoData -IncludeGPOObject -ReturnSingleObject -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
}
|
||||
$Object['PermissionsPerRow'] = $Object['Permissions'] | ForEach-Object { $_ }
|
||||
$Object['PermissionsAnalysis'] = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$Object
|
||||
}
|
||||
Processing = {
|
||||
@@ -33,6 +34,8 @@
|
||||
$Script:Reporting['GPOPermissionsAdministrative']['Variables']['WillFix']++
|
||||
$Script:Reporting['GPOPermissionsAdministrative']['Variables']['WillFixPerDomain'][$GPO[0].DomainName]++
|
||||
}
|
||||
# lets create table and add it there
|
||||
$Script:Reporting['GPOPermissionsAdministrative']['Data'].'PermissionsAnalysis'.Add($Analysis)
|
||||
}
|
||||
if ($Script:Reporting['GPOPermissionsAdministrative']['Variables']['WillFix'] -gt 0) {
|
||||
$Script:Reporting['GPOPermissionsAdministrative']['ActionRequired'] = $true
|
||||
@@ -88,11 +91,16 @@
|
||||
} -Title 'Group Policy Permissions' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policy Administrative Users Analysis' {
|
||||
New-HTMLSection -Name 'Group Policy Administrative Users Permissions Summary' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPermissionsAdministrative']['Data'].PermissionsPerRow -Filtering {
|
||||
New-HTMLTableCondition -Name 'Permission' -Value '' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
} -PagingOptions 7, 15, 30, 45, 60
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policy Administrative Users Analysis' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPermissionsAdministrative']['Data'].PermissionsAnalysis -Filtering {
|
||||
# New-HTMLTableCondition -Name 'Permission' -Value '' -BackgroundColor Salmon -ComparisonType string -Row
|
||||
} -PagingOptions 7, 15, 30, 45, 60
|
||||
}
|
||||
if ($Script:Reporting['Settings']['HideSteps'] -eq $false) {
|
||||
New-HTMLSection -Name 'Steps to fix Group Policy Administrative Users' {
|
||||
New-HTMLContainer {
|
||||
@@ -184,7 +192,7 @@
|
||||
}
|
||||
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
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,583 @@
|
||||
$GPOZaurrPermissionsAnalysis = [ordered] @{
|
||||
Name = 'Group Policy Permissions Analysis'
|
||||
Enabled = $true
|
||||
Action = $null
|
||||
Data = $null
|
||||
Execute = {
|
||||
$Object = [ordered] @{
|
||||
Permissions = Get-GPOZaurrPermission -ReturnSecurityWhenNoData -IncludeGPOObject -ReturnSingleObject -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
}
|
||||
$Object['PermissionsPerRow'] = $Object['Permissions'] | ForEach-Object { $_ }
|
||||
$Object['PermissionsAnalysis'] = Get-GPOZaurrPermissionAnalysis -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -Permissions $Object.Permissions
|
||||
$Object['PermissionsIssues'] = Get-GPOZaurrPermissionIssue -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
$Object
|
||||
}
|
||||
Processing = {
|
||||
# Create Per Domain Variables
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixAdministrativePerDomain'] = @{}
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAdministrativePerDomain'] = @{}
|
||||
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixAuthenticatedUsersPerDomain'] = @{}
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAuthenticatedUsersPerDomain'] = @{}
|
||||
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixSystemPerDomain'] = @{}
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchSystemPerDomain'] = @{}
|
||||
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixUnknownPerDomain'] = @{}
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchUnknownPerDomain'] = @{}
|
||||
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotFixPerDomain'] = @{}
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixPerDomain'] = @{}
|
||||
|
||||
$Script:Reporting['GPOPermissions']['Variables']['ReadPerDomain'] = @{}
|
||||
$Script:Reporting['GPOPermissions']['Variables']['CouldNotReadPerDomain'] = @{}
|
||||
$Script:Reporting['GPOPermissions']['Variables']['TotalPerDomain'] = @{}
|
||||
|
||||
foreach ($GPO in $Script:Reporting['GPOPermissions']['Data'].PermissionsIssues) {
|
||||
# Create Per Domain Variables
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['CouldNotReadPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['CouldNotReadPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['ReadPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['ReadPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['TotalPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['TotalPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if ($GPO.PermissionIssue) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['CouldNotRead']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['CouldNotReadPerDomain'][$GPO.DomainName]++
|
||||
} else {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['Read']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['ReadPerDomain'][$GPO.DomainName]++
|
||||
}
|
||||
$Script:Reporting['GPOPermissions']['Variables']['Total']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['TotalPerDomain'][$GPO.DomainName]++
|
||||
}
|
||||
foreach ($GPO in $Script:Reporting['GPOPermissions']['Data'].PermissionsAnalysis) {
|
||||
# Create Per Domain Variables
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['WillFixPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['WillNotFixPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotFixPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['WillFixAdministrativePerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixAdministrativePerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAdministrativePerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAdministrativePerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['WillFixAuthenticatedUsersPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixAuthenticatedUsersPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['WillFixSystemPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixSystemPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchSystemPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchSystemPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['WillFixUnknownPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixUnknownPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
if (-not $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchUnknownPerDomain'][$GPO.DomainName]) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchUnknownPerDomain'][$GPO.DomainName] = 0
|
||||
}
|
||||
|
||||
# Checks
|
||||
if ($GPO.Administrative -eq $true) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAdministrative']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAdministrativePerDomain'][$GPO.DomainName]++
|
||||
} else {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixAdministrative']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixAdministrativePerDomain'][$GPO.DomainName]++
|
||||
}
|
||||
|
||||
if ($GPO.AuthenticatedUsers -eq $true) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAuthenticatedUsers']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAuthenticatedUsersPerDomain'][$GPO.DomainName]++
|
||||
} else {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixAuthenticatedUsers']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixAuthenticatedUsersPerDomain'][$GPO.DomainName]++
|
||||
}
|
||||
|
||||
if ($GPO.System -eq $true) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchSystem']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchSystemPerDomain'][$GPO.DomainName]++
|
||||
} else {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixSystem']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixSystemPerDomain'][$GPO.DomainName]++
|
||||
}
|
||||
|
||||
if ($GPO.Unknown -eq $false) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchUnknown']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotTouchUnknownPerDomain'][$GPO.DomainName]++
|
||||
} else {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixUnknown']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixUnknownPerDomain'][$GPO.DomainName]++
|
||||
}
|
||||
|
||||
if ($GPO.Status -eq $false) {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFix']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillFixPerDomain'][$GPO.DomainName]++
|
||||
} else {
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotFix']++
|
||||
$Script:Reporting['GPOPermissions']['Variables']['WillNotFixPerDomain'][$GPO.DomainName]++
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['GPOPermissions']['Variables']['WillFix'] -gt 0 -or $Script:Reporting['GPOPermissions']['Variables']['CouldNotRead'] -gt 0) {
|
||||
$Script:Reporting['GPOPermissions']['ActionRequired'] = $true
|
||||
} else {
|
||||
$Script:Reporting['GPOPermissions']['ActionRequired'] = $false
|
||||
}
|
||||
}
|
||||
Variables = @{
|
||||
# Issues / Couldnt read report
|
||||
Read = 0
|
||||
ReadPerDomain = $null
|
||||
CouldNotRead = 0
|
||||
CouldNotReadPerDomain = $null
|
||||
TotalPerDomain = $null
|
||||
Total = 0
|
||||
# Permissions analysis
|
||||
WillFix = 0
|
||||
WillNotFix = 0
|
||||
WillFixAdministrative = 0
|
||||
WillNotTouchAdministrative = 0
|
||||
WillFixUnknown = 0
|
||||
WillNotTouchUnknown = 0
|
||||
WillNotTouchSystem = 0
|
||||
WillFixSystem = 0
|
||||
WillNotTouchAuthenticatedUsers = 0
|
||||
WillFixAuthenticatedUsers = 0
|
||||
WillNotTouchAuthenticatedUsersPerDomain = $null
|
||||
WillFixAuthenticatedUsersPerDomain = $null
|
||||
WillNotTouchSystemPerDomain = $null
|
||||
WillFixSystemPerDomain = $null
|
||||
WillFixAdministrativePerDomain = $null
|
||||
WillNotTouchAdministrativePerDomain = $null
|
||||
WillNotFixPerDomain = $null
|
||||
WillFixPerDomain = $null
|
||||
WillFixUnknownPerDomain = $null
|
||||
WillNotTouchUnknownPerDomain = $null
|
||||
}
|
||||
Summary = {
|
||||
New-HTMLText -FontSize 10pt -Text "When GPO is created it gets a handful of standard permissions. Those are:"
|
||||
New-HTMLList {
|
||||
New-HTMLListItem -Text "NT AUTHORITY\Authenticated Users with GpoApply permissions"
|
||||
New-HTMLListItem -Text "Domain Admins and Enterprise Admins with Edit/Delete/Modify permissions"
|
||||
New-HTMLListItem -Text "SYSTEM account with Edit/Delete/Modify permissions"
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text "But then IT people change those permissions to their own needs. While most changes make sense and are required to be able to target proper groups of people, some changes are not required or even bad. "
|
||||
|
||||
New-HTMLText -Text "First problem relates to NT AUTHORITY\Authenticated Users" -FontSize 10pt -FontWeight bold -TextDecoration underline -Alignment center
|
||||
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"When GPO is created one of the permissions that are required for proper functioning of Group Policies is NT AUTHORITY\Authenticated Users. "
|
||||
"Some Administrators don't follow best practices and trying to remove GpoApply permission, remove also GpoRead permission from a GPO which can have consequences. "
|
||||
"On June 14th, 2016 Microsoft released [HotFix](https://support.microsoft.com/en-gb/help/3159398/ms16-072-description-of-the-security-update-for-group-policy-june-14-2) that requires Authenticated Users to be present on all Group Policies to function properly. "
|
||||
"MS16-072 changes the security context with which user group policies are retrieved. "
|
||||
"This by-design behavior change protects customers’ computers from a security vulnerability. "
|
||||
}
|
||||
New-HTMLList {
|
||||
New-HTMLListItem -Text "Before MS16-072 is installed, user group policies were retrieved by using the user’s security context. "
|
||||
New-HTMLListItem -Text "After MS16-072 is installed, user group policies are retrieved by using the computer's security context."
|
||||
} -FontSize 10pt
|
||||
|
||||
New-HTMLText -FontSize 10pt -Text @(
|
||||
"Unfortunetly it's not as simple as it sounds. While checking for permissions mostly works fine, it's possible a Group Policy has totally removed account permissions from being able to asses any of it. ",
|
||||
"The account we're using "
|
||||
"$($Env:USERDOMAIN)\$($Env:USERNAME.ToUpper())",
|
||||
" may simply not have enough permisions to properly asses permissions for a GPO. "
|
||||
"Therefore we're using dual assesment for this situation, where first assesment is checking for GPO visibility or lack of it, and second assesment is checking for direct permissions assignement. "
|
||||
"We just were able to detect the problem, but hopefully higher level account (Domain Admin) should be able to provide full assesment. "
|
||||
) -FontWeight normal, normal, bold, normal -Color None, None, BlueDiamond, none, none
|
||||
|
||||
New-HTMLText -FontSize 10pt -Text "First assesment results: " -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text "Group Policies couldn't read at all: ", $Script:Reporting['GPOPermissions']['Variables']['CouldNotRead'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies with permissions allowing read: ", $Script:Reporting['GPOPermissions']['Variables']['Read'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOPermissions']['Variables']['CouldNotReadPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text @(
|
||||
"$Domain requires ",
|
||||
$Script:Reporting['GPOPermissions']['Variables']['CouldNotReadPerDomain'][$Domain],
|
||||
" changes out of ",
|
||||
$Script:Reporting['GPOPermissions']['Variables']['TotalPerDomain'][$Domain],
|
||||
"."
|
||||
) -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
|
||||
New-HTMLText -FontSize 10pt -Text "Second Assesment results " -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies requiring Authenticated Users with GpoRead permission: ', $Script:Reporting['GPOPermissions']['Variables']['WillFixAuthenticatedUsers'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which don't require changes: ", $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAuthenticatedUsers'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOPermissions']['Variables']['WillFixAuthenticatedUsersPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOPermissions']['Variables']['WillFixAuthenticatedUsersPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text "Second problem relates to Domain Admins and Enterprise Admins" -FontSize 10pt -FontWeight bold -TextDecoration underline -Alignment center
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"When GPO is created by default it gets Domain Admins and Enterprise Admins with Edit/Delete/Modify Security permissions. "
|
||||
"For some reason, some Administrators remove those permissions or modify them when they shouldn't touch those at all. "
|
||||
"Since having Edit/Delete/Modify Security permissions doesn't affect GPOApply permissions there's no reason to remove Domain Admins or Enterprise Admins from permissions, or limit their rights. "
|
||||
"Domain Admins and Enterprise Admins have to have either GPOEditModify permissions or at the very least GPOCustom. "
|
||||
"When GPOCustom is set it usually means there's a mix of Allow and Deny permission in place (for example deny GPOApply). "
|
||||
"In such case we're assuming you know what you're doing. However it's always possible to review those permissions, as those are marked in the table for review. "
|
||||
} -LineBreak
|
||||
|
||||
New-HTMLText -FontSize 10pt -Text "Assesment results " -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies requiring Administrative permission fix: ', $Script:Reporting['GPOPermissions']['Variables']['WillFixAdministrative'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which don't require changes: ", $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAdministrative'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOPermissions']['Variables']['WillFixAdministrativePerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOPermissions']['Variables']['WillFixAdministrativePerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
|
||||
New-HTMLText -Text "Third problem relates to SYSTEM account" -FontSize 10pt -FontWeight bold -TextDecoration underline -Alignment center
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"When GPO is created by default it gets SYSTEM account with Edit/Delete/Modify Security permissions. "
|
||||
"For some reason, some Administrators remove those permissions or modify them when they shouldn't touch those at all. "
|
||||
"Since having Edit/Delete/Modify Security permissions doesn't affect GPOApply permissions there's no reason to remove SYSTEM from permissions, or limit their rights. "
|
||||
} -LineBreak
|
||||
|
||||
New-HTMLText -FontSize 10pt -Text "Assesment results " -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies requiring SYSTEM permission fix: ', $Script:Reporting['GPOPermissions']['Variables']['WillFixSystem'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which don't require changes: ", $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchSystem'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOPermissions']['Variables']['WillFixSystemPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOPermissions']['Variables']['WillFixSystemPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt
|
||||
|
||||
New-HTMLText -Text "Fourth problem relates to UNKNOWN SID" -FontSize 10pt -FontWeight bold -TextDecoration underline -Alignment center
|
||||
New-HTMLText -FontSize 10pt -TextBlock {
|
||||
"Sometimes groups or users are deleted in Active Directory and unfortunetly their permissions are not cleaned automatically. "
|
||||
"Those are left in-place and stay there forever until removed. "
|
||||
} -LineBreak
|
||||
|
||||
New-HTMLText -FontSize 10pt -Text "Assesment results " -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Group Policies requiring Unknown permission removal: ', $Script:Reporting['GPOPermissions']['Variables']['WillFixUnknown'] -FontWeight normal, bold
|
||||
New-HTMLListItem -Text "Group Policies which don't require changes: ", $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchUnknown'] -FontWeight normal, bold
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -Text 'Following domains require actions (permissions required):' -FontSize 10pt -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
foreach ($Domain in $Script:Reporting['GPOPermissions']['Variables']['WillFixUnknownPerDomain'].Keys) {
|
||||
New-HTMLListItem -Text "$Domain requires ", $Script:Reporting['GPOPermissions']['Variables']['WillFixUnknownPerDomain'][$Domain], " changes." -FontWeight normal, bold, normal
|
||||
}
|
||||
} -FontSize 10pt -LineBreak
|
||||
# Just in case report is too big and the full file is not attached
|
||||
New-HTMLText -FontSize 10pt -Text "To generate up to date report please execute: " -FontWeight bold
|
||||
New-HTMLList -Type Unordered {
|
||||
New-HTMLListItem -Text 'Install-Module GPOZaurr -Force', ' or ', ' install module manually.' -Color RoyalBlue, None, None
|
||||
New-HTMLListItem -Text 'Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrGPOPermissionsBefore.html -Verbose -Type GPOPermissions' -Color RoyalBlue
|
||||
} -FontSize 10pt
|
||||
New-HTMLText -FontSize 10pt -Text 'Steps above will generate above summary with more details allowing you to get up to date report and steps on how to fix it.'
|
||||
}
|
||||
Solution = {
|
||||
New-HTMLSection -Invisible {
|
||||
New-HTMLPanel {
|
||||
& $Script:GPOConfiguration['GPOPermissions']['Summary']
|
||||
}
|
||||
New-HTMLPanel {
|
||||
New-HTMLChart {
|
||||
New-ChartBarOptions -Type barStacked
|
||||
New-ChartLegend -Name 'Yes', 'No' -Color SpringGreen, Salmon
|
||||
New-ChartBar -Name 'Visible Permissions' -Value $Script:Reporting['GPOPermissions']['Variables']['Read'], $Script:Reporting['GPOPermissions']['Variables']['CouldNotRead']
|
||||
New-ChartBar -Name 'Overall Permissions' -Value $Script:Reporting['GPOPermissions']['Variables']['WillNotFix'], $Script:Reporting['GPOPermissions']['Variables']['WillFix']
|
||||
New-ChartBar -Name 'Administrative Permissions' -Value $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAdministrative'], $Script:Reporting['GPOPermissions']['Variables']['WillFixAdministrative']
|
||||
New-ChartBar -Name 'Authenticated Users Permissions' -Value $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchAdministrative'], $Script:Reporting['GPOPermissions']['Variables']['WillFixAuthenticatedUsers']
|
||||
New-ChartBar -Name 'System Permissions' -Value $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchSystem'], $Script:Reporting['GPOPermissions']['Variables']['WillFixSystem']
|
||||
New-ChartBar -Name 'Unknown Permissions' -Value $Script:Reporting['GPOPermissions']['Variables']['WillNotTouchUnknown'], $Script:Reporting['GPOPermissions']['Variables']['WillFixUnknown']
|
||||
} -Title 'Group Policy Permissions' -TitleAlignment center
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policy Visibility Analysis' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPermissions']['Data'].PermissionsIssues -Filtering {
|
||||
New-HTMLTableCondition -Name 'PermissionIssue' -Value $true -BackgroundColor Salmon -ComparisonType string -Row
|
||||
} -PagingOptions 7, 15, 30, 45, 60 -DefaultSortColumn PermissionIssue -DefaultSortOrder Descending
|
||||
}
|
||||
New-HTMLSection -Name 'Group Policy Permissions Analysis' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLText -Text 'Explanation to table columns:' -FontSize 10pt
|
||||
New-HTMLList {
|
||||
New-HTMLListItem -FontWeight bold, normal -Text "Status", " - means GPO has at least one problem with permissions. "
|
||||
New-HTMLListItem -FontWeight bold, normal -Text "Administrative", " - means GPO has problem with either Domain Admins or Enterprise Admins not having proper permissions. "
|
||||
New-HTMLListItem -FontWeight bold, normal -Text "AuthenticatedUsers", " - means GPO has Authenticated Users missing either as GPOApply or GPORead. "
|
||||
New-HTMLListItem -FontWeight bold, normal -Text "System", " - means GPO has SYSTEM permission missing or lacking proper permissions. "
|
||||
New-HTMLListItem -FontWeight bold, normal -Text "DomainAdmins", " - means GPO has Domain Admins missing or having wrong permissions. "
|
||||
New-HTMLListItem -FontWeight bold, normal -Text "EnterpriseAdmins", " - means GPO has Enterprise Admins missing or having wrong permissions. "
|
||||
} -FontSize 10pt
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPermissions']['Data'].PermissionsAnalysis -Filtering {
|
||||
New-HTMLTableCondition -Name 'Status' -Value 'True' -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'Administrative' -Value 'True' -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'AuthenticatedUsers' -Value 'True' -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'System' -Value 'True' -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'Unknown' -Value 'False' -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'DomainAdmins' -Value 'True' -BackgroundColor SpringGreen -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'EnterpriseAdmins' -Value 'True' -BackgroundColor SpringGreen -ComparisonType string
|
||||
|
||||
# Mark as warning
|
||||
New-HTMLTableCondition -Name 'DomainAdminsPermission' -Value 'GpoCustom' -BackgroundColor Moccasin -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'EnterpriseAdminsPermission' -Value 'GpoCustom' -BackgroundColor Moccasin -ComparisonType string
|
||||
# Reverse
|
||||
New-HTMLTableCondition -Name 'Status' -Value 'True' -BackgroundColor Salmon -ComparisonType string -Operator ne
|
||||
New-HTMLTableCondition -Name 'Administrative' -Value 'True' -BackgroundColor Salmon -ComparisonType string -Operator ne
|
||||
New-HTMLTableCondition -Name 'AuthenticatedUsers' -Value 'True' -BackgroundColor Salmon -ComparisonType string -Operator ne
|
||||
New-HTMLTableCondition -Name 'System' -Value 'True' -BackgroundColor Salmon -ComparisonType string -Operator ne
|
||||
New-HTMLTableCondition -Name 'Unknown' -Value 'False' -BackgroundColor Salmon -ComparisonType string -Operator ne
|
||||
New-HTMLTableCondition -Name 'DomainAdmins' -Value 'True' -BackgroundColor Salmon -ComparisonType string -Operator ne
|
||||
New-HTMLTableCondition -Name 'EnterpriseAdmins' -Value 'True' -BackgroundColor Salmon -ComparisonType string -Operator ne
|
||||
|
||||
New-TableEvent -TableID 'GPOPermissionsAll' -SourceColumnName 'GUID' -TargetColumnID 1 # TargetColumnID 1 eq GUID on the other table
|
||||
} -PagingOptions 7, 15, 30, 45, 60
|
||||
}
|
||||
}
|
||||
New-HTMLSection -Name 'All Permissions' {
|
||||
New-HTMLTable -DataTable $Script:Reporting['GPOPermissions']['Data'].PermissionsPerRow -Filtering {
|
||||
New-HTMLTableHeader -Names 'PrincipalNetBiosName', 'PrincipalDistinguishedName', 'PrincipalDomainName', 'PrincipalName', 'PrincipalSid', 'PrincipalSidType' -Title 'Account Information'
|
||||
New-HTMLTableCondition -Name 'Permission' -Value 'GpoEditDeleteModifySecurity' -BackgroundColor HotPink -ComparisonType string -Operator eq
|
||||
New-HTMLTableCondition -Name 'Permission' -Value 'GpoCustom' -BackgroundColor Moccasin -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'Permission' -Value 'GpoApply' -BackgroundColor Orange -ComparisonType string
|
||||
New-HTMLTableCondition -Name 'Permission' -Value 'GpoRead' -BackgroundColor MediumSpringGreen -ComparisonType string -Operator eq
|
||||
New-HTMLTableCondition -Name 'PrincipalSidType' -Value 'Unknown' -BackgroundColor Salmon -ComparisonType string -Operator eq
|
||||
} -PagingOptions 7, 15, 30, 45, 60 -DataTableID 'GPOPermissionsAll'
|
||||
}
|
||||
if ($Script:Reporting['Settings']['HideSteps'] -eq $false) {
|
||||
New-HTMLSection -Name 'Steps to fix Group Policy Administrative Users' {
|
||||
New-HTMLContainer {
|
||||
New-HTMLSpanStyle -FontSize 10pt {
|
||||
New-HTMLWizard {
|
||||
New-HTMLWizardStep -Name 'Prepare environment' {
|
||||
New-HTMLText -Text "To be able to execute actions in automated way please install required modules. Those modules will be installed straight from Microsoft PowerShell Gallery."
|
||||
New-HTMLCodeBlock -Code {
|
||||
Install-Module GPOZaurr -Force
|
||||
Import-Module GPOZaurr -Force
|
||||
} -Style powershell
|
||||
New-HTMLText -Text "Using force makes sure newest version is downloaded from PowerShellGallery regardless of what is currently installed. Once installed you're ready for next step."
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Prepare report' {
|
||||
New-HTMLText -Text "Depending when this report was run you may want to prepare new report before proceeding with fixing Group Policy Authenticated Users. To generate new report please use:"
|
||||
New-HTMLCodeBlock -Code {
|
||||
Invoke-GPOZaurr -FilePath $Env:UserProfile\Desktop\GPOZaurrGPOPermissionsBefore.html -Verbose -Type GPOPermissions
|
||||
}
|
||||
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. "
|
||||
"GPOs with problems will be those not having any value for Permission/PermissionType columns. "
|
||||
"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 {
|
||||
# This gets all permissions
|
||||
$AllPermissions = Get-GPOZaurrPermission
|
||||
$AllPermissions | Format-Table
|
||||
|
||||
# this analyses permissions
|
||||
$PermissionsAnalysis = Get-GPOZaurrPermissionAnalysis
|
||||
$PermissionsAnalysis | Format-Table
|
||||
}
|
||||
New-HTMLText -Text "It provides same data as you see in table above just doesn't prettify it for you."
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Make a backup (optional)' {
|
||||
New-HTMLText -TextBlock {
|
||||
"The process of fixing GPO Permissions does NOT touch GPO content. It simply adds permissionss on AD and SYSVOL at the same time for given GPO. "
|
||||
"However, it's always good to have a backup before executing changes that may impact Active Directory. "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
$GPOSummary = Backup-GPOZaurr -BackupPath "$Env:UserProfile\Desktop\GPO" -Verbose -Type All
|
||||
$GPOSummary | Format-Table # only if you want to display output of backup
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Above command when executed will make a backup to Desktop, create GPO folder and within it it will put all those GPOs. "
|
||||
}
|
||||
}
|
||||
New-HTMLWizardStep -Name 'Add Authenticated Users permissions' {
|
||||
New-HTMLText -Text @(
|
||||
"Following command will find any GPO which doesn't have Authenticated User as GpoRead or GpoApply and will add it as GpoRead. ",
|
||||
"This change doesn't change GpoApply permission, therefore it won't change to whom the GPO applies to. ",
|
||||
"It ensures that COMPUTERS can read GPO properly to be able to Apply it. ",
|
||||
"Make sure when running it for the first time to run it with ",
|
||||
"WhatIf",
|
||||
" parameter as shown below to prevent accidental adding of permissions."
|
||||
) -FontWeight normal, normal, normal, normal, bold, normal -Color Black, Black, Black, Black, Red, Black
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type AuthenticatedUsers -PermissionType GpoRead -All -WhatIf -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type AuthenticatedUsers -PermissionType GpoRead -All -WhatIf -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be changed matches expected data."
|
||||
} -LineBreak
|
||||
New-HTMLText -Text "Once happy with results please follow with command (this will start fixing process): " -LineBreak -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type AuthenticatedUsers -PermissionType GpoRead -All -Verbose -LimitProcessing 2
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type AuthenticatedUsers -PermissionType GpoRead -All -Verbose -LimitProcessing 2 -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed adds Authenticated Users (GpoRead permission) only on first X non-compliant Group Policies. "
|
||||
"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 'Add Administrative Groups permissions' {
|
||||
New-HTMLText -Text @(
|
||||
"Following command will find any GPO which doesn't have Domain Admins and Enterprise Admins added with GpoEditDeleteModifySecurity and will add it as GpoEditDeleteModifySecurity. ",
|
||||
"This change doesn't change GpoApply permission, therefore it won't change to whom the GPO applies to. ",
|
||||
"It ensures that Domain Admins and Enterprise Admins can manage GPO. ",
|
||||
"Make sure when running it for the first time to run it with ",
|
||||
"WhatIf",
|
||||
" parameter as shown below to prevent accidental adding of permissions."
|
||||
) -FontWeight normal, normal, normal, normal, bold, normal -Color Black, Black, Black, Black, Red, Black
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type Administrative -PermissionType GpoEditDeleteModifySecurity -All -WhatIf -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type Administrative -PermissionType GpoEditDeleteModifySecurity -All -WhatIf -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be changed matches expected data."
|
||||
} -LineBreak
|
||||
New-HTMLText -Text "Once happy with results please follow with command (this will start fixing process): " -LineBreak -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type Administrative -PermissionType GpoEditDeleteModifySecurity -All -Verbose -LimitProcessing 2
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type Administrative -PermissionType GpoEditDeleteModifySecurity -All -Verbose -LimitProcessing 2 -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed adds Enterprise Admins or/and Domain Admins (GpoEditDeleteModifySecurity permission) only on first X non-compliant Group Policies. "
|
||||
"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 'Add SYSTEM permissions' {
|
||||
New-HTMLText -Text @(
|
||||
"Following command will find any GPO which doesn't have SYSTEM account added with GpoEditDeleteModifySecurity and will add it as GpoEditDeleteModifySecurity. ",
|
||||
"This change doesn't change GpoApply permission, therefore it won't change to whom the GPO applies to. ",
|
||||
"It ensures that SYSTEM can manage GPO. ",
|
||||
"Make sure when running it for the first time to run it with ",
|
||||
"WhatIf",
|
||||
" parameter as shown below to prevent accidental adding of permissions."
|
||||
) -FontWeight normal, normal, normal, normal, bold, normal -Color Black, Black, Black, Black, Red, Black
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type WellKnownAdministrative -PermissionType GpoEditDeleteModifySecurity -All -WhatIf -Verbose
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type WellKnownAdministrative -PermissionType GpoEditDeleteModifySecurity -All -WhatIf -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be changed matches expected data."
|
||||
} -LineBreak
|
||||
New-HTMLText -Text "Once happy with results please follow with command (this will start fixing process): " -LineBreak -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type WellKnownAdministrative -PermissionType GpoEditDeleteModifySecurity -All -Verbose -LimitProcessing 2
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Add-GPOZaurrPermission -Type WellKnownAdministrative -PermissionType GpoEditDeleteModifySecurity -All -Verbose -LimitProcessing 2 -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed adds SYSTEM account (GpoEditDeleteModifySecurity permission) only on first X non-compliant Group Policies. "
|
||||
"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 'Remove UNKNOWN permissions' {
|
||||
New-HTMLText -Text @(
|
||||
"Following command will find any GPO which has an unknown SID and will remove it. ",
|
||||
"This change doesn't change any other permissions. ",
|
||||
"It ensures that GPOs have no unknown permissions present. ",
|
||||
"Make sure when running it for the first time to run it with ",
|
||||
"WhatIf",
|
||||
" parameter as shown below to prevent accidental adding of permissions."
|
||||
) -FontWeight normal, normal, normal, normal, bold, normal -Color Black, Black, Black, Black, Red, Black
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrPermission -Verbose -Type Unknown -WhatIf
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrPermission -Verbose -Type Unknown -WhatIf -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"After execution please make sure there are no errors, make sure to review provided output, and confirm that what is about to be changed matches expected data."
|
||||
} -LineBreak
|
||||
New-HTMLText -Text "Once happy with results please follow with command (this will start fixing process): " -LineBreak -FontWeight bold
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrPermission -Verbose -Type Unknown -LimitProcessing 2
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"Alternatively for multi-domain scenario, if you have limited Domain Admin credentials to a single domain please use following command: "
|
||||
}
|
||||
New-HTMLCodeBlock -Code {
|
||||
Remove-GPOZaurrPermission -Verbose -Type Unknown -LimitProcessing 2 -IncludeDomains 'YourDomainYouHavePermissionsFor'
|
||||
}
|
||||
New-HTMLText -TextBlock {
|
||||
"This command when executed removes only first X unknwon permissions from Group Policies. "
|
||||
"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\GPOZaurrGPOPermissionsAfter.html -Verbose -Type GPOPermissions
|
||||
}
|
||||
New-HTMLText -Text "If everything is healthy in the report you're done! Enjoy rest of the day!" -Color BlueDiamond
|
||||
}
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Script:Reporting['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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
Execute = {
|
||||
[ordered] @{
|
||||
Permissions = Get-GPOZaurrPermission -Type AuthenticatedUsers -ReturnSecurityWhenNoData -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
Issues = Get-GPOZaurrPermissionIssue
|
||||
Issues = Get-GPOZaurrPermissionIssue -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains
|
||||
}
|
||||
}
|
||||
Processing = {
|
||||
@@ -93,7 +93,7 @@
|
||||
} -FontStyle italic -FontSize 10pt -FontWeight bold -LineBreak
|
||||
New-HTMLText -FontSize 10pt -Text @(
|
||||
"There are two parts to this assesment. Reading all Group Policies Permissions that account ",
|
||||
$($Env:USERNAME.ToUpper()),
|
||||
"$($Env:USERDOMAIN)\$($Env:USERNAME.ToUpper())",
|
||||
" has permissions to read and provide detailed assesment about permissions. ",
|
||||
"Second assesment checks for permissions that this account is not able to read at all, and therefore it has no visibility about permissions set on it. "
|
||||
"We just were able to detect the problem, but hopefully higher level account (Domain Admin) should be able to provide full assesment. "
|
||||
@@ -249,7 +249,7 @@
|
||||
}
|
||||
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
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
}
|
||||
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
|
||||
} -RemoveDoneStepOnNavigateBack -Theme arrows -ToolbarButtonPosition center -EnableAllAnchors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
function New-GPOZaurrExclusions {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[alias('ExcludeGroupPolicies', 'ExclusionsCode', 'ExclusionsArray')][Parameter(Position = 1)][object] $Exclusions
|
||||
)
|
||||
|
||||
if ($Exclusions) {
|
||||
if ($Exclusions -is [scriptblock]) {
|
||||
#$Script:Reporting[$T]['Exclusions'] = $Exclusions
|
||||
#$Script:Reporting[$T]['ExclusionsCode'] = $Exclusions
|
||||
[string] $Code = @(
|
||||
"`$Exclusions = {"
|
||||
" " + $Exclusions.ToString()
|
||||
"}"
|
||||
)
|
||||
$Code
|
||||
}
|
||||
if ($Exclusions -is [Array]) {
|
||||
#$Script:Reporting[$T]['Exclusions'] = $Exclusions
|
||||
#$ExclusionsArray = $Exclusions
|
||||
[string] $Code = @(
|
||||
'$Exclusions = @('
|
||||
[System.Environment]::NewLine
|
||||
foreach ($Exclusion in $Exclusions) {
|
||||
" `"$Exclusion`"" + [System.Environment]::NewLine
|
||||
}
|
||||
[System.Environment]::NewLine
|
||||
')'
|
||||
)
|
||||
$Code
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,11 @@
|
||||
function New-GPOZaurrReportHTML {
|
||||
function New-GPOZaurrReportHTML {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[System.Collections.IDictionary] $Support,
|
||||
[string] $Path,
|
||||
[switch] $Offline,
|
||||
[switch] $Online,
|
||||
[switch] $Open
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$PSDefaultParameterValues = @{
|
||||
"New-HTMLTable:WarningAction" = 'SilentlyContinue'
|
||||
}
|
||||
@@ -194,5 +189,5 @@ function New-GPOZaurrReportHTML {
|
||||
}
|
||||
}
|
||||
}
|
||||
} -Online:(-not $Offline.IsPresent) -Open:$Open.IsPresent -FilePath $Path
|
||||
} -Online:$Online.IsPresent -Open:$Open.IsPresent -FilePath $Path
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
$Script:GPOConfiguration = [ordered] @{
|
||||
GPOOrphans = $GPOZaurrOrphans
|
||||
GPOBroken = $GPOZaurrOrphans
|
||||
GPOBrokenLink = $GPOZaurrBrokenLink
|
||||
GPOOwners = $GPOZaurrOwners
|
||||
GPOConsistency = $GPOZaurrConsistency
|
||||
GPODuplicates = $GPOZaurrDuplicates
|
||||
GPOOrganizationalUnit = $GPOZaurrOrganizationalUnit
|
||||
GPOList = $GPOZaurrList
|
||||
GPOLinks = $GPOZaurrLinks
|
||||
GPOPassword = $GPOZaurrPassword
|
||||
GPOPermissions = $GPOZaurrPermissions
|
||||
GPOPermissions = $GPOZaurrPermissionsAnalysis
|
||||
GPOPermissionsAdministrative = $GPOZaurrPermissionsAdministrative
|
||||
GPOPermissionsRead = $GPOZaurrPermissionsRead
|
||||
GPOPermissionsRoot = $GPOZaurrPermissionsRoot
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
$Script:GPODitionary = [ordered] @{
|
||||
AccountPolicies = [ordered] @{
|
||||
AccountPolicies = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'SecuritySettings'
|
||||
@@ -14,7 +14,7 @@
|
||||
ConvertTo-XMLAccountPolicy -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
Audit = [ordered] @{
|
||||
Audit = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'SecuritySettings'
|
||||
@@ -36,7 +36,7 @@
|
||||
ConvertTo-XMLAudit -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
Autologon = [ordered] @{
|
||||
Autologon = [ordered] @{
|
||||
# We want to process this based on other report called RegistrySettings
|
||||
# This is because registry settings can be stored in Collections or nested within other registry settings
|
||||
# The original function ConvertTo-XMLRegistryAutologon was processing it in limited ordered and potentially would skip some entries.
|
||||
@@ -50,7 +50,7 @@
|
||||
ConvertTo-XMLRegistryAutologonOnReport -GPO $GPO
|
||||
}
|
||||
}
|
||||
AutoPlay = @{
|
||||
AutoPlay = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -65,7 +65,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/AutoPlay Policies*' -SingleObject
|
||||
}
|
||||
}
|
||||
Biometrics = @{
|
||||
Biometrics = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -78,7 +78,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Biometrics*'
|
||||
}
|
||||
}
|
||||
Bitlocker = @{
|
||||
Bitlocker = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -95,7 +95,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/BitLocker Drive Encryption*' -SingleObject
|
||||
}
|
||||
}
|
||||
ControlPanel = [ordered]@{
|
||||
ControlPanel = [ordered]@{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -110,7 +110,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Control Panel' -SingleObject
|
||||
}
|
||||
}
|
||||
ControlPanelAddRemove = [ordered]@{
|
||||
ControlPanelAddRemove = [ordered]@{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -125,7 +125,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Control Panel/Add or Remove Programs' -SingleObject
|
||||
}
|
||||
}
|
||||
ControlPanelDisplay = [ordered]@{
|
||||
ControlPanelDisplay = [ordered]@{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -140,7 +140,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Control Panel/Display' -SingleObject
|
||||
}
|
||||
}
|
||||
ControlPanelPersonalization = [ordered]@{
|
||||
ControlPanelPersonalization = [ordered]@{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -155,7 +155,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Control Panel/Personalization' -SingleObject
|
||||
}
|
||||
}
|
||||
ControlPanelPrinters = [ordered]@{
|
||||
ControlPanelPrinters = [ordered]@{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -170,7 +170,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Control Panel/Printers' -SingleObject
|
||||
}
|
||||
}
|
||||
ControlPanelPrograms = [ordered]@{
|
||||
ControlPanelPrograms = [ordered]@{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -185,7 +185,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Control Panel/Programs' -SingleObject
|
||||
}
|
||||
}
|
||||
ControlPanelRegional = [ordered]@{
|
||||
ControlPanelRegional = [ordered]@{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -200,7 +200,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Control Panel/Regional and Language Options' -SingleObject
|
||||
}
|
||||
}
|
||||
CredentialsDelegation = @{
|
||||
CredentialsDelegation = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -215,7 +215,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'System/Credentials Delegation*' -SingleObject
|
||||
}
|
||||
}
|
||||
CustomInternationalSettings = [ordered]@{
|
||||
CustomInternationalSettings = [ordered]@{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -230,7 +230,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Custom International Settings*' -SingleObject
|
||||
}
|
||||
}
|
||||
Desktop = @{
|
||||
Desktop = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -245,7 +245,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Desktop*' -SingleObject
|
||||
}
|
||||
}
|
||||
DnsClient = @{
|
||||
DnsClient = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -260,7 +260,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Network/DNS Client*' -SingleObject
|
||||
}
|
||||
}
|
||||
DriveMapping = [ordered] @{
|
||||
DriveMapping = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'DriveMapSettings'
|
||||
@@ -275,7 +275,7 @@
|
||||
ConvertTo-XMLDriveMapSettings -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
EventLog = [ordered] @{
|
||||
EventLog = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'SecuritySettings'
|
||||
@@ -290,7 +290,7 @@
|
||||
ConvertTo-XMLEventLog -GPO $GPO
|
||||
}
|
||||
}
|
||||
EventForwarding = @{
|
||||
EventForwarding = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -305,7 +305,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Event Forwarding*' -SingleObject
|
||||
}
|
||||
}
|
||||
EventLogService = @{
|
||||
EventLogService = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -320,7 +320,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Event Log Service*' -SingleObject
|
||||
}
|
||||
}
|
||||
FileExplorer = @{
|
||||
FileExplorer = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -335,7 +335,22 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/File Explorer*' -SingleObject
|
||||
}
|
||||
}
|
||||
FolderRedirection = @{
|
||||
FolderRedirection = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'FolderRedirectionSettings'
|
||||
Settings = 'Folder'
|
||||
}
|
||||
)
|
||||
GPOPath = 'Windows Settings -> Folder Redirection'
|
||||
Code = {
|
||||
ConvertTo-XMLFolderRedirection -GPO $GPO
|
||||
}
|
||||
CodeSingle = {
|
||||
ConvertTo-XMLFolderRedirection -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
FolderRedirectionPolicy = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -350,7 +365,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'System/Folder Redirection' -SingleObject
|
||||
}
|
||||
}
|
||||
FSLogix = @{
|
||||
FSLogix = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -365,7 +380,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'FSLogix' -SingleObject
|
||||
}
|
||||
}
|
||||
GoogleChrome = @{
|
||||
GoogleChrome = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -384,7 +399,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Google Chrome', 'Google/Google Chrome', 'Google Chrome - Default Settings (users can override)' -SingleObject
|
||||
}
|
||||
}
|
||||
GroupPolicy = @{
|
||||
GroupPolicy = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -399,7 +414,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'System/Group Policy*' -SingleObject
|
||||
}
|
||||
}
|
||||
InternetCommunicationManagement = @{
|
||||
InternetCommunicationManagement = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -414,7 +429,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'System/Internet Communication Management*' -SingleObject
|
||||
}
|
||||
}
|
||||
InternetExplorer = @{
|
||||
InternetExplorer = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -429,7 +444,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Internet Explorer*', 'Composants Windows/Celle Internet Explorer' -SingleObject
|
||||
}
|
||||
}
|
||||
InternetExplorerZones = [ordered] @{
|
||||
InternetExplorerZones = [ordered] @{
|
||||
ByReports = @(
|
||||
@{
|
||||
Report = 'RegistrySettings'
|
||||
@@ -440,7 +455,7 @@
|
||||
ConvertTo-XMLRegistryInternetExplorerZones -GPO $GPO
|
||||
}
|
||||
}
|
||||
KDC = @{
|
||||
KDC = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -455,7 +470,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'System/KDC' -SingleObject
|
||||
}
|
||||
}
|
||||
LAPS = @{
|
||||
LAPS = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -470,7 +485,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'LAPS' -SingleObject
|
||||
}
|
||||
}
|
||||
Lithnet = @{
|
||||
Lithnet = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -486,7 +501,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Lithnet/Password Protection for Active Directory*' -SingleObject
|
||||
}
|
||||
}
|
||||
LocalUsers = [ordered] @{
|
||||
LocalUsers = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'LugsSettings'
|
||||
@@ -501,7 +516,7 @@
|
||||
ConvertTo-XMLLocalUser -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
LocalGroups = [ordered] @{
|
||||
LocalGroups = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'LugsSettings'
|
||||
@@ -516,7 +531,7 @@
|
||||
ConvertTo-XMLLocalGroups -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
Logon = @{
|
||||
Logon = @{
|
||||
Types = @(
|
||||
@{ Category = 'RegistrySettings'; Settings = 'Policy' }
|
||||
)
|
||||
@@ -528,7 +543,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'System/Logon*' -SingleObject
|
||||
}
|
||||
}
|
||||
MicrosoftOutlook2002 = @{
|
||||
MicrosoftOutlook2002 = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -543,7 +558,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Microsoft Outlook 2002*' -SingleObject
|
||||
}
|
||||
}
|
||||
MicrosoftEdge = @{
|
||||
MicrosoftEdge = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -562,7 +577,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Microsoft Edge*', 'Windows Components/Microsoft Edge', 'Windows Components/Edge UI' -SingleObject
|
||||
}
|
||||
}
|
||||
MicrosoftOutlook2003 = @{
|
||||
MicrosoftOutlook2003 = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -580,7 +595,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Microsoft Office Outlook 2003*', 'Outlook 2003 RPC Encryption' -SingleObject
|
||||
}
|
||||
}
|
||||
MicrosoftOutlook2010 = @{
|
||||
MicrosoftOutlook2010 = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -595,7 +610,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Microsoft Outlook 2010*' -SingleObject
|
||||
}
|
||||
}
|
||||
MicrosoftOutlook2013 = @{
|
||||
MicrosoftOutlook2013 = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -610,7 +625,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Microsoft Outlook 2013*' -SingleObject
|
||||
}
|
||||
}
|
||||
MicrosoftOutlook2016 = @{
|
||||
MicrosoftOutlook2016 = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -625,7 +640,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Microsoft Outlook 2016*' -SingleObject
|
||||
}
|
||||
}
|
||||
MicrosoftManagementConsole = @{
|
||||
MicrosoftManagementConsole = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -640,7 +655,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Microsoft Management Console*' -SingleObject
|
||||
}
|
||||
}
|
||||
NetMeeting = @{
|
||||
NetMeeting = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -655,7 +670,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/NetMeeting*' -SingleObject
|
||||
}
|
||||
}
|
||||
MSSLegacy = @{
|
||||
MSSLegacy = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -670,7 +685,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'MSS (Legacy)' -SingleObject
|
||||
}
|
||||
}
|
||||
MSSecurityGuide = @{
|
||||
MSSecurityGuide = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -685,7 +700,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'MS Security Guide' -SingleObject
|
||||
}
|
||||
}
|
||||
OneDrive = @{
|
||||
OneDrive = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -700,7 +715,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/OneDrive*' -SingleObject
|
||||
}
|
||||
}
|
||||
Policies = @{
|
||||
Policies = @{
|
||||
Comment = "This isn't really translated"
|
||||
Types = @(
|
||||
@{
|
||||
@@ -716,7 +731,7 @@
|
||||
ConvertTo-XMLPolicies -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
Printers = @{
|
||||
Printers = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'PrintersSettings'
|
||||
@@ -735,7 +750,7 @@
|
||||
ConvertTo-XMLPrinter -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
PrintersPolicies = @{
|
||||
PrintersPolicies = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -753,7 +768,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Printers*', 'Control Panel/Printers*' -SingleObject
|
||||
}
|
||||
}
|
||||
PublicKeyPoliciesCertificates = [ordered] @{
|
||||
PublicKeyPoliciesCertificates = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'PublicKeySettings'
|
||||
@@ -774,10 +789,10 @@
|
||||
)
|
||||
GPOPath = 'Policies -> Windows Settings -> Security Settings -> Public Key Policies'
|
||||
Code = {
|
||||
ConvertTo-XMLGenericPublicKey -GPO $GPO
|
||||
ConvertTo-XMLCertificates -GPO $GPO
|
||||
}
|
||||
CodeSingle = {
|
||||
ConvertTo-XMLGenericPublicKey -GPO $GPO -SingleObject
|
||||
ConvertTo-XMLCertificates -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
<#
|
||||
@@ -805,7 +820,7 @@
|
||||
}
|
||||
}
|
||||
#>
|
||||
PublicKeyPoliciesAutoEnrollment = [ordered] @{
|
||||
PublicKeyPoliciesAutoEnrollment = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'PublicKeySettings'
|
||||
@@ -820,7 +835,7 @@
|
||||
ConvertTo-XMLGenericPublicKey -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
PublicKeyPoliciesEFS = [ordered] @{
|
||||
PublicKeyPoliciesEFS = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'PublicKeySettings'
|
||||
@@ -835,7 +850,7 @@
|
||||
ConvertTo-XMLGenericPublicKey -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
PublicKeyPoliciesRootCA = [ordered] @{
|
||||
PublicKeyPoliciesRootCA = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'PublicKeySettings'
|
||||
@@ -850,7 +865,7 @@
|
||||
ConvertTo-XMLGenericPublicKey -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
PublicKeyPoliciesEnrollmentPolicy = @{
|
||||
PublicKeyPoliciesEnrollmentPolicy = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -867,7 +882,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'System/Internet Communication Management*' -SingleObject
|
||||
}
|
||||
}
|
||||
RegistrySetting = [ordered] @{
|
||||
RegistrySetting = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -882,7 +897,7 @@
|
||||
ConvertTo-XMLGenericPublicKey -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
RegistrySettings = [ordered] @{
|
||||
RegistrySettings = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -897,7 +912,7 @@
|
||||
ConvertTo-XMLRegistrySettings -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
OnlineAssistance = @{
|
||||
OnlineAssistance = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -912,7 +927,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Online Assistance*' -SingleObject
|
||||
}
|
||||
}
|
||||
RemoteAssistance = @{
|
||||
RemoteAssistance = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -927,7 +942,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'System/Remote Assistance*' -SingleObject
|
||||
}
|
||||
}
|
||||
RemoteDesktopServices = @{
|
||||
RemoteDesktopServices = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -942,7 +957,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Remote Desktop Services*' -SingleObject
|
||||
}
|
||||
}
|
||||
RSSFeeds = @{
|
||||
RSSFeeds = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -957,7 +972,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/RSS Feeds*' -SingleObject
|
||||
}
|
||||
}
|
||||
Scripts = [ordered] @{
|
||||
Scripts = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'Scripts'
|
||||
@@ -972,7 +987,7 @@
|
||||
ConvertTo-XMLScripts -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
SecurityOptions = [ordered] @{
|
||||
SecurityOptions = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'SecuritySettings'
|
||||
@@ -987,7 +1002,7 @@
|
||||
ConvertTo-XMLSecurityOptions -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
SoftwareInstallation = [ordered] @{
|
||||
SoftwareInstallation = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'SoftwareInstallationSettings'
|
||||
@@ -1002,7 +1017,7 @@
|
||||
ConvertTo-XMLSoftwareInstallation -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
SystemServices = [ordered] @{
|
||||
SystemServices = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'SecuritySettings'
|
||||
@@ -1018,7 +1033,7 @@
|
||||
ConvertTo-XMLSystemServices -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
SystemServicesNT = [ordered] @{
|
||||
SystemServicesNT = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'ServiceSettings'
|
||||
@@ -1052,7 +1067,7 @@
|
||||
}
|
||||
}
|
||||
#>
|
||||
TaskScheduler = [ordered] @{
|
||||
TaskScheduler = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'ScheduledTasksSettings'
|
||||
@@ -1068,7 +1083,7 @@
|
||||
ConvertTo-XMLTaskScheduler -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
TaskSchedulerPolicies = @{
|
||||
TaskSchedulerPolicies = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -1101,7 +1116,7 @@
|
||||
}
|
||||
}
|
||||
#>
|
||||
UserRightsAssignment = [ordered] @{
|
||||
UserRightsAssignment = [ordered] @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'SecuritySettings'
|
||||
@@ -1116,7 +1131,7 @@
|
||||
ConvertTo-XMLUserRightsAssignment -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsDefender = @{
|
||||
WindowsDefender = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -1131,7 +1146,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsDefenderExploitGuard = @{
|
||||
WindowsDefenderExploitGuard = @{
|
||||
# this needs improvements because of DropDownList
|
||||
Types = @(
|
||||
@{
|
||||
@@ -1147,7 +1162,103 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsHelloForBusiness = @{
|
||||
# WindowsFirewall = @{
|
||||
# # Contains only one setting showing version
|
||||
# Types = @(
|
||||
# @{
|
||||
# Category = 'WindowsFirewallSettings'
|
||||
# Settings = 'GlobalSettings'
|
||||
# }
|
||||
# )
|
||||
# GPOPath = 'Policies -> Windows Settings -> Security Settings -> Windows Firewall with Advanced Security'
|
||||
# Code = {
|
||||
# ConvertTo-XMLWindowsFirewall -GPO $GPO
|
||||
# }
|
||||
# CodeSingle = {
|
||||
# ConvertTo-XMLWindowsFirewall -GPO $GPO -SingleObject
|
||||
# }
|
||||
# }
|
||||
WindowsFirewallConnectionSecurityRules = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'WindowsFirewallSettings'
|
||||
Settings = 'ConnectionSecurityRules'
|
||||
}
|
||||
)
|
||||
GPOPath = 'Policies -> Windows Settings -> Security Settings -> Windows Firewall with Advanced Security'
|
||||
Code = {
|
||||
ConvertTo-XMLWindowsFirewallSecurityRules -GPO $GPO
|
||||
}
|
||||
CodeSingle = {
|
||||
ConvertTo-XMLWindowsFirewallSecurityRules -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsFirewallConnectionSecurityAuthentication = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'WindowsFirewallSettings'
|
||||
Settings = 'Phase1AuthenticationSets'
|
||||
}
|
||||
@{
|
||||
Category = 'WindowsFirewallSettings'
|
||||
Settings = 'Phase2AuthenticationSets'
|
||||
}
|
||||
#@{
|
||||
# Category = 'WindowsFirewallSettings'
|
||||
# Settings = 'DefaultPhase1CryptoSet'
|
||||
#}
|
||||
)
|
||||
GPOPath = 'Policies -> Windows Settings -> Security Settings -> Windows Firewall with Advanced Security'
|
||||
Code = {
|
||||
ConvertTo-XMLWindowsFirewallConnectionSecurityAuthentiation -GPO $GPO
|
||||
}
|
||||
CodeSingle = {
|
||||
ConvertTo-XMLWindowsFirewallConnectionSecurityAuthentiation -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsFirewallProfiles = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'WindowsFirewallSettings'
|
||||
Settings = 'DomainProfile'
|
||||
}
|
||||
@{
|
||||
Category = 'WindowsFirewallSettings'
|
||||
Settings = 'PublicProfile'
|
||||
}
|
||||
@{
|
||||
Category = 'WindowsFirewallSettings'
|
||||
Settings = 'PrivateProfile'
|
||||
}
|
||||
)
|
||||
GPOPath = 'Policies -> Windows Settings -> Security Settings -> Windows Firewall with Advanced Security'
|
||||
Code = {
|
||||
ConvertTo-XMLWindowsFirewallProfile -GPO $GPO
|
||||
}
|
||||
CodeSingle = {
|
||||
ConvertTo-XMLWindowsFirewallProfile -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsFirewallRules = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'WindowsFirewallSettings'
|
||||
Settings = 'InboundFirewallRules'
|
||||
}
|
||||
@{
|
||||
Category = 'WindowsFirewallSettings'
|
||||
Settings = 'OutboundFirewallRules'
|
||||
}
|
||||
)
|
||||
GPOPath = 'Policies -> Windows Settings -> Security Settings -> Windows Firewall with Advanced Security -> '
|
||||
Code = {
|
||||
ConvertTo-XMLWindowsFirewallRules -GPO $GPO
|
||||
}
|
||||
CodeSingle = {
|
||||
ConvertTo-XMLWindowsFirewallRules -GPO $GPO -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsHelloForBusiness = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -1162,7 +1273,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Hello For Business*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsInstaller = @{
|
||||
WindowsInstaller = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -1177,7 +1288,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Installer*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsLogon = @{
|
||||
WindowsLogon = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -1192,7 +1303,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Logon Options*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsMediaPlayer = @{
|
||||
WindowsMediaPlayer = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -1207,7 +1318,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Media Player*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsMessenger = @{
|
||||
WindowsMessenger = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -1222,7 +1333,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Messenger*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsPowerShell = @{
|
||||
WindowsPowerShell = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -1237,7 +1348,7 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows PowerShell*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsRemoteManagement = @{
|
||||
WindowsRemoteManagement = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
@@ -1252,7 +1363,22 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Remote Management (WinRM)*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsUpdate = @{
|
||||
WindowsTimeService = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
Settings = 'Policy'
|
||||
}
|
||||
)
|
||||
GPOPath = 'Policies -> Administrative Templates -> System/Windows Time Service'
|
||||
Code = {
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'System/Windows Time Service*'
|
||||
}
|
||||
CodeSingle = {
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'System/Windows Time Service*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsUpdate = @{
|
||||
Types = @(
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
)
|
||||
$Differences = @{ }
|
||||
$SysvolHash = @{ }
|
||||
|
||||
$GPOGUIDS = $GPOs.ID.GUID
|
||||
$GPOGUIDS = ConvertFrom-DistinguishedName -DistinguishedName $GPOs.DistinguishedName
|
||||
$SysVolPath = "\\$($Server)\SYSVOL\$Domain\Policies"
|
||||
Write-Verbose "Get-GPOZaurrBroken - Processing SYSVOL from \\$($Server)\SYSVOL\$Domain\Policies"
|
||||
try {
|
||||
@@ -19,10 +18,10 @@
|
||||
$Sysvol = $Null
|
||||
}
|
||||
foreach ($_ in $SYSVOL) {
|
||||
$GUID = $_.Name -replace '{' -replace '}'
|
||||
$GUID = $_.Name
|
||||
$SysvolHash[$GUID] = $_
|
||||
}
|
||||
$Files = $SYSVOL.Name -replace '{' -replace '}'
|
||||
$Files = $SYSVOL.Name
|
||||
if ($Files) {
|
||||
$Comparing = Compare-Object -ReferenceObject $GPOGUIDS -DifferenceObject $Files -IncludeEqual
|
||||
foreach ($_ in $Comparing) {
|
||||
@@ -30,8 +29,10 @@
|
||||
# we skip policy definitions
|
||||
continue
|
||||
}
|
||||
$ADStatus = $PoliciesAD[$_.InputObject]
|
||||
if ($_.SideIndicator -eq '==') {
|
||||
$Found = 'Exists'
|
||||
#$Found = 'Exists'
|
||||
$Found = $ADStatus
|
||||
} elseif ($_.SideIndicator -eq '<=') {
|
||||
$Found = 'Not available on SYSVOL'
|
||||
} elseif ($_.SideIndicator -eq '=>') {
|
||||
@@ -41,8 +42,10 @@
|
||||
$Found = 'Not available in AD'
|
||||
}
|
||||
} else {
|
||||
# This shouldn't happen at all
|
||||
$Found = 'Orphaned GPO'
|
||||
}
|
||||
|
||||
$Differences[$_.InputObject] = $Found
|
||||
}
|
||||
}
|
||||
@@ -50,85 +53,60 @@
|
||||
$Count = 0
|
||||
foreach ($GPO in $GPOS) {
|
||||
$Count++
|
||||
Write-Verbose "Get-GPOZaurrBroken - Processing [$($GPO.DomainName)]($Count/$($GPOS.Count)) $($GPO.DisplayName)"
|
||||
if ($null -ne $SysvolHash[$GPO.Id.GUID].FullName) {
|
||||
$FullPath = $SysvolHash[$GPO.Id.GUID].FullName
|
||||
try {
|
||||
$ACL = Get-Acl -Path $SysvolHash[$GPO.Id.GUID].FullName -ErrorAction Stop -Verbose:$false
|
||||
$Owner = $ACL.Owner
|
||||
$ErrorMessage = ''
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrBroken - ACL reading (1) failed for $FullPath with error: $($_.Exception.Message)"
|
||||
$ACL = $null
|
||||
$Owner = ''
|
||||
$ErrorMessage = $_.Exception.Message
|
||||
}
|
||||
$GPOGuid = ConvertFrom-DistinguishedName -DistinguishedName $GPO.DistinguishedName
|
||||
if ($GPO.DisplayName) {
|
||||
$GPODisplayName = $GPO.DisplayName
|
||||
$GPOName = $GPO.Name
|
||||
Write-Verbose "Get-GPOZaurrBroken - Processing [$($Domain)]($Count/$($GPOS.Count)) $($GPO.DisplayName)"
|
||||
} else {
|
||||
$FullPath = -join ($SysVolPath, "\{$($GPO.Id.Guid)}")
|
||||
$ACL = $null
|
||||
$Owner = ''
|
||||
$GPOName = $GPOGuid
|
||||
$GPODisplayName = $GPOGuid
|
||||
Write-Verbose "Get-GPOZaurrBroken - Processing [$($Domain)]($Count/$($GPOS.Count)) $($GPOGuid)"
|
||||
}
|
||||
if ($null -ne $SysvolHash[$GPOGuid].FullName) {
|
||||
$FullPath = $SysvolHash[$GPOGuid].FullName
|
||||
$ErrorMessage = ''
|
||||
} else {
|
||||
$FullPath = -join ($SysVolPath, "\$($GPOGuid)")
|
||||
$ErrorMessage = 'Not found on SYSVOL'
|
||||
}
|
||||
if ($null -eq $Differences[$GPO.Id.Guid]) {
|
||||
$SysVolStatus = 'Unknown Issue'
|
||||
if ($null -eq $Differences[$GPOGuid]) {
|
||||
$SysVolStatus = 'Unknown issue'
|
||||
} else {
|
||||
$SysVolStatus = $Differences[$GPO.Id.Guid]
|
||||
$SysVolStatus = $Differences[$GPOGuid]
|
||||
}
|
||||
[PSCustomObject] @{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DisplayName = $GPODisplayName
|
||||
Status = $SysVolStatus
|
||||
DomainName = $GPO.DomainName
|
||||
DomainName = $Domain
|
||||
SysvolServer = $Server
|
||||
SysvolStatus = $SysVolStatus
|
||||
GpoStatus = $GPO.GpoStatus
|
||||
Owner = $GPO.Owner
|
||||
FileOwner = $Owner
|
||||
Id = $GPO.Id.Guid
|
||||
ObjectClass = $GPO.ObjectClass
|
||||
Id = $GPOName
|
||||
Path = $FullPath
|
||||
DistinguishedName = -join ("CN={", $GPO.Id.Guid, "},", $PoliciesSearchBase)
|
||||
DistinguishedName = -join ("CN=", $GPOGuid, ",", $PoliciesSearchBase)
|
||||
Description = $GPO.Description
|
||||
CreationTime = $GPO.CreationTime
|
||||
ModificationTime = $GPO.ModificationTime
|
||||
UserVersion = $GPO.UserVersion
|
||||
ComputerVersion = $GPO.ComputerVersion
|
||||
WmiFilter = $GPO.WmiFilter
|
||||
CreationTime = $GPO.Created
|
||||
ModificationTime = $GPO.Modified
|
||||
Error = $ErrorMessage
|
||||
}
|
||||
}
|
||||
# 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
|
||||
Write-Verbose "Get-GPOZaurrBroken - Processing SYSVOL differences"
|
||||
foreach ($_ in $Differences.Keys) {
|
||||
if ($Differences[$_] -in 'Not available in AD', 'Permissions issue') {
|
||||
if ($Differences[$_] -in 'Not available in AD') {
|
||||
$FullPath = $SysvolHash[$_].FullName
|
||||
try {
|
||||
$ACL = Get-Acl -Path $FullPath -ErrorAction Stop
|
||||
$Owner = $ACL.Owner
|
||||
$ErrorMessage = ''
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrBroken - 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
|
||||
ObjectClass = ''
|
||||
Id = $_
|
||||
Path = $FullPath
|
||||
DistinguishedName = -join ("CN={", $_, "},", $PoliciesSearchBase)
|
||||
DistinguishedName = -join ("CN=", $_, ",", $PoliciesSearchBase)
|
||||
Description = $null
|
||||
CreationTime = $SysvolHash[$_].CreationTime
|
||||
ModificationTime = $SysvolHash[$_].LastWriteTime
|
||||
UserVersion = $null
|
||||
ComputerVersion = $null
|
||||
WmiFilter = $null
|
||||
Error = $ErrorMessage
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
}
|
||||
}
|
||||
#>
|
||||
if (-not $PermissionsAnalysis['Skip']) {
|
||||
if (-not $PermissionsAnalysis.'Skip') {
|
||||
if (-not $GPOPermissions) {
|
||||
# This is bad - things went wrong
|
||||
Write-Warning "Add-GPOZaurrPermission - Couldn't get permissions for GPO. Things aren't what they should be. Skipping!"
|
||||
@@ -118,7 +118,7 @@
|
||||
# We asked, we got response, now we need to check if maybe we're missing one of the two administrative groups
|
||||
if ($Type -eq 'Administrative') {
|
||||
# this is a case where something was returned. Be it Domain Admins or Enterprise Admins or both. But we still need to check because it may have been Domain Admins from other domain or just one of the two required groups
|
||||
if ($PermissionsAnalysis['DomainAdmins'] -eq $false) {
|
||||
if ($PermissionsAnalysis.'DomainAdmins' -eq $false) {
|
||||
$Principal = $ADAdministrativeGroups[$GPO.DomainName]['DomainAdmins']
|
||||
Write-Verbose "Add-GPOZaurrPermission - Adding permission $PermissionType for $($Principal) to $($GPO.DisplayName) at $($GPO.DomainName)"
|
||||
$CountFixed++
|
||||
@@ -132,7 +132,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($PermissionsAnalysis['EnterpriseAdmins'] -eq $false) {
|
||||
if ($PermissionsAnalysis.'EnterpriseAdmins' -eq $false) {
|
||||
$Principal = $ADAdministrativeGroups[$ForestInformation.Forest.RootDomain]['EnterpriseAdmins']
|
||||
Write-Verbose "Add-GPOZaurrPermission - Adding permission $PermissionType for $($Principal) to $($GPO.DisplayName) at $($GPO.DomainName)"
|
||||
$CountFixed++
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function Clear-GPOZaurrSysvolDFSR {
|
||||
function Clear-GPOZaurrSysvolDFSR {
|
||||
[cmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[alias('ForestName')][string] $Forest,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function ConvertFrom-CSExtension {
|
||||
function ConvertFrom-CSExtension {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[string[]] $CSE,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function Find-CSExtension {
|
||||
function Find-CSExtension {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[string[]] $CSE,
|
||||
|
||||
+11
-5
@@ -47,6 +47,10 @@
|
||||
if ($OwnerOnly -or $PermissionsOnly -and $Type) {
|
||||
Write-Warning "Get-GPOZaurr - Using PermissionOnly or OwnerOnly with Type is not supported. "
|
||||
}
|
||||
if (-not $GPOPath) {
|
||||
# This is needed, because Get-GPOReport doesn't deliver full scope of links, just some of it. It doesn't cover OUs with blocked inheritance, sites or crosslinked
|
||||
$LinksSummaryCache = Get-GPOZaurrLink -AsHashTable -Summary -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
}
|
||||
}
|
||||
Process {
|
||||
if (-not $GPOPath) {
|
||||
@@ -86,7 +90,7 @@
|
||||
Write-Warning "Get-GPOZaurr - Failed to get [$($GPO.DomainName)]($Count/$($GroupPolicies.Count)) $($GPO.DisplayName) GPOReport: $($_.Exception.Message). Skipping."
|
||||
continue
|
||||
}
|
||||
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $GPO -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups -ReturnObject:$ReturnObject.IsPresent -ExcludeGroupPolicies $ExcludeGPO -Type $Type
|
||||
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -GPO $GPO -PermissionsOnly:$PermissionsOnly.IsPresent -ADAdministrativeGroups $ADAdministrativeGroups -ReturnObject:$ReturnObject.IsPresent -ExcludeGroupPolicies $ExcludeGPO -Type $Type -LinksSummaryCache $LinksSummaryCache
|
||||
} else {
|
||||
$GPO
|
||||
}
|
||||
@@ -95,10 +99,12 @@
|
||||
} else {
|
||||
foreach ($Path in $GPOPath) {
|
||||
Write-Verbose "Get-GPOZaurr - Getting GPO content from XML files"
|
||||
Get-ChildItem -LiteralPath $Path -Recurse -Filter *.xml | ForEach-Object {
|
||||
$XMLContent = [XML]::new()
|
||||
$XMLContent.Load($_.FullName)
|
||||
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -PermissionsOnly:$PermissionsOnly.IsPresent -ExcludeGroupPolicies $ExcludeGPO -Type $Type
|
||||
Get-ChildItem -LiteralPath $Path -Recurse -Filter *.xml -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
if ($_.Name -ne 'GPOList.xml') {
|
||||
$XMLContent = [XML]::new()
|
||||
$XMLContent.Load($_.FullName)
|
||||
Get-XMLGPO -OwnerOnly:$OwnerOnly.IsPresent -XMLContent $XMLContent -PermissionsOnly:$PermissionsOnly.IsPresent -ExcludeGroupPolicies $ExcludeGPO -Type $Type
|
||||
}
|
||||
}
|
||||
Write-Verbose "Get-GPOZaurr - Finished GPO content from XML files"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,47 @@
|
||||
function Get-GPOZaurrBroken {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Detects broken or otherwise damaged Group Policies
|
||||
|
||||
.DESCRIPTION
|
||||
Detects broken or otherwise damaged Group Policies providing insight whether GPO exists in both AD and SYSVOL.
|
||||
It provides few statuses:
|
||||
- Permissions issue - means account couldn't read GPO due to permissions
|
||||
- ObjectClass issue - means that ObjectClass is of type Container, rather than expected groupPolicyContainer
|
||||
- Not available on SYSVOL - means SYSVOL data is missing, yet AD metadata is available
|
||||
- Not available in AD - means AD metadata is missing, yet SYSVOL data is available
|
||||
- Exists - means AD metadata and SYSVOL data are available
|
||||
|
||||
.PARAMETER Forest
|
||||
Target different Forest, by default current forest is used
|
||||
|
||||
.PARAMETER ExcludeDomains
|
||||
Exclude domain from search, by default whole forest is scanned
|
||||
|
||||
.PARAMETER ExcludeDomainControllers
|
||||
Exclude specific domain controllers, by default there are no exclusions, as long as VerifyDomainControllers switch is enabled. Otherwise this parameter is ignored.
|
||||
|
||||
.PARAMETER IncludeDomains
|
||||
Include only specific domains, by default whole forest is scanned
|
||||
|
||||
.PARAMETER IncludeDomainControllers
|
||||
Include only specific domain controllers, by default all domain controllers are included, as long as VerifyDomainControllers switch is enabled. Otherwise this parameter is ignored.
|
||||
|
||||
.PARAMETER SkipRODC
|
||||
Skip Read-Only Domain Controllers. By default all domain controllers are included.
|
||||
|
||||
.PARAMETER ExtendedForestInformation
|
||||
Ability to provide Forest Information from another command to speed up processing
|
||||
|
||||
.PARAMETER VerifyDomainControllers
|
||||
Forces cmdlet to check GPO Existance on Domain Controllers rather then per domain
|
||||
|
||||
.EXAMPLE
|
||||
Get-GPOZaurrBroken -Verbose | Format-Table
|
||||
|
||||
.NOTES
|
||||
General notes
|
||||
#>
|
||||
[alias('Get-GPOZaurrSysvol')]
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
@@ -8,7 +51,6 @@
|
||||
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
|
||||
[alias('DomainControllers')][string[]] $IncludeDomainControllers,
|
||||
[switch] $SkipRODC,
|
||||
[Array] $GPOs,
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation,
|
||||
[switch] $VerifyDomainControllers
|
||||
)
|
||||
@@ -21,31 +63,31 @@
|
||||
$PoliciesAD = @{}
|
||||
if ($SystemsContainer) {
|
||||
$PoliciesSearchBase = -join ("CN=Policies,", $SystemsContainer)
|
||||
$PoliciesInAD = Get-ADObject -SearchBase $PoliciesSearchBase -SearchScope OneLevel -Filter * -Server $QueryServer
|
||||
$PoliciesInAD = Get-ADObject -SearchBase $PoliciesSearchBase -SearchScope OneLevel -Filter * -Server $QueryServer -Properties Name, gPCFileSysPath, DisplayName, DistinguishedName, Description, Created, Modified, ObjectClass, ObjectGUID
|
||||
foreach ($Policy in $PoliciesInAD) {
|
||||
$GUIDFromDN = ConvertFrom-DistinguishedName -DistinguishedName $Policy.DistinguishedName
|
||||
$GUIDFromDN = $GUIDFromDN -replace '{' -replace '}'
|
||||
$GUID = $Policy.Name -replace '{' -replace '}'
|
||||
if ($GUID -and $GUIDFromDN) {
|
||||
$PoliciesAD[$GUIDFromDN] = 'Exists'
|
||||
if ($Policy.ObjectClass -eq 'Container') {
|
||||
# This usually means GPO deletion process somehow failed and while object itself stayed it isn't groupPolicyContainer anymore
|
||||
$PoliciesAD[$GUIDFromDN] = 'ObjectClass issue'
|
||||
} else {
|
||||
$PoliciesAD[$GUIDFromDN] = 'Permissions issue'
|
||||
$GUID = $Policy.Name
|
||||
if ($GUID -and $GUIDFromDN) {
|
||||
$PoliciesAD[$GUIDFromDN] = 'Exists'
|
||||
} else {
|
||||
$PoliciesAD[$GUIDFromDN] = 'Permissions issue'
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Warning "Get-GPOZaurrBroken - Couldn't get GPOs from $Domain. Skipping"
|
||||
}
|
||||
Try {
|
||||
[Array]$GPOs = Get-GPO -All -Domain $Domain -Server $QueryServer
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrBroken - Couldn't get GPOs from $Domain. Error: $($_.Exception.Message)"
|
||||
continue
|
||||
}
|
||||
if ($GPOs.Count -ge 2) {
|
||||
if ($PoliciesInAD.Count -ge 2) {
|
||||
if (-not $VerifyDomainControllers) {
|
||||
Test-SysVolFolders -GPOs $GPOs -Server $Domain -Domain $Domain -PoliciesAD $PoliciesAD -PoliciesSearchBase $PoliciesSearchBase
|
||||
Test-SysVolFolders -GPOs $PoliciesInAD -Server $Domain -Domain $Domain -PoliciesAD $PoliciesAD -PoliciesSearchBase $PoliciesSearchBase
|
||||
} else {
|
||||
foreach ($Server in $ForestInformation['DomainDomainControllers']["$Domain"]) {
|
||||
Write-Verbose "Get-GPOZaurrBroken - Processing $Domain \ $($Server.HostName.Trim())"
|
||||
Test-SysVolFolders -GPOs $GPOs -Server $Server.Hostname -Domain $Domain -PoliciesAD $PoliciesAD -PoliciesSearchBase $PoliciesSearchBase
|
||||
Test-SysVolFolders -GPOs $PoliciesInAD -Server $Server.Hostname -Domain $Domain -PoliciesAD $PoliciesAD -PoliciesSearchBase $PoliciesSearchBase
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
function Get-GPOZaurrBrokenLink {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Finds any GPO link that doesn't have a matching GPO (already removed GPO).
|
||||
|
||||
.DESCRIPTION
|
||||
Finds any GPO link that doesn't have a matching GPO (already removed GPO).
|
||||
|
||||
.PARAMETER Forest
|
||||
Target different Forest, by default current forest is used
|
||||
|
||||
.PARAMETER ExcludeDomains
|
||||
Exclude domain from search, by default whole forest is scanned
|
||||
|
||||
.PARAMETER IncludeDomains
|
||||
Include only specific domains, by default whole forest is scanned
|
||||
|
||||
.PARAMETER ExtendedForestInformation
|
||||
Ability to provide Forest Information from another command to speed up processing
|
||||
|
||||
.EXAMPLE
|
||||
Get-GPOZaurrBrokenLink -Verbose | Format-Table -AutoSize *
|
||||
|
||||
.EXAMPLE
|
||||
Get-GPOZaurrBrokenLink -Verbose -IncludeDomains ad.evotec.pl | Format-Table -AutoSize *
|
||||
|
||||
.NOTES
|
||||
General notes
|
||||
#>
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[alias('ForestName')][string] $Forest,
|
||||
[string[]] $ExcludeDomains,
|
||||
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation
|
||||
)
|
||||
$ErrorFound = $false
|
||||
$PoliciesAD = @{}
|
||||
# We need to request all GPOS from Forest. Requesting just for any domain won't be enough
|
||||
$ForestInformation = Get-WinADForestDetails -Forest $Forest -Extended # -Extended
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
$QueryServer = $ForestInformation['QueryServers']["$Domain"].HostName[0]
|
||||
$SystemsContainer = $ForestInformation['DomainsExtended'][$Domain].SystemsContainer
|
||||
if ($SystemsContainer) {
|
||||
$PoliciesSearchBase = -join ("CN=Policies,", $SystemsContainer)
|
||||
try {
|
||||
$PoliciesInAD = Get-ADObject -ErrorAction Stop -SearchBase $PoliciesSearchBase -SearchScope OneLevel -Filter * -Server $QueryServer -Properties Name, gPCFileSysPath, DisplayName, DistinguishedName, Description, Created, Modified, ObjectClass, ObjectGUID
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrBrokenLink - An error occured while searching $PoliciesSearchBase. Error $($_.Exception.Message). Please resolve this before continuing."
|
||||
$ErrorFound = $true
|
||||
break
|
||||
}
|
||||
foreach ($Policy in $PoliciesInAD) {
|
||||
$GUIDFromDN = ConvertFrom-DistinguishedName -DistinguishedName $Policy.DistinguishedName
|
||||
# $Key = "$($Domain)$($GuidFromDN)"
|
||||
$Key = $Policy.DistinguishedName
|
||||
if ($Policy.ObjectClass -eq 'Container') {
|
||||
# This usually means GPO deletion process somehow failed and while object itself stayed it isn't groupPolicyContainer anymore
|
||||
$PoliciesAD[$Key] = 'ObjectClass issue'
|
||||
} else {
|
||||
$GUID = $Policy.Name
|
||||
if ($GUID -and $GUIDFromDN) {
|
||||
$PoliciesAD[$Key] = 'Exists'
|
||||
} else {
|
||||
$PoliciesAD[$Key] = 'Permissions issue'
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Warning "Get-GPOZaurrBroken - Couldn't get GPOs from $Domain. Skipping"
|
||||
}
|
||||
}
|
||||
if ($ErrorFound) {
|
||||
return
|
||||
}
|
||||
# In case of links we can request here whatever user requested.
|
||||
# This will search for broken links in domain user requested
|
||||
$ForestInformation = Get-WinADForestDetails -Forest $Forest -Extended -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
$Links = Get-GPOZaurrLinkLoop -Linked 'All' -ForestInformation $ForestInformation
|
||||
foreach ($Link in $Links) {
|
||||
if (-not $PoliciesAD[$Link.GPODistinguishedName]) {
|
||||
$Link
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
function Get-GPOZaurrFilesPolicyDefinition {
|
||||
function Get-GPOZaurrFilesPolicyDefinition {
|
||||
[alias('Get-GPOZaurrFilesPolicyDefinitions')]
|
||||
[cmdletbinding()]
|
||||
param(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function Get-GPOZaurrFolders {
|
||||
function Get-GPOZaurrFolders {
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[ValidateSet('All', 'Netlogon', 'Sysvol')][string[]] $Type = 'All',
|
||||
|
||||
@@ -1,8 +1,49 @@
|
||||
function Get-GPOZaurrInheritance {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Short description
|
||||
|
||||
.DESCRIPTION
|
||||
Long description
|
||||
|
||||
.PARAMETER IncludeBlockedObjects
|
||||
Include OU's with blocked inheritance. Default disabled
|
||||
|
||||
.PARAMETER OnlyBlockedInheritance
|
||||
Show only OU's with blocked inheritance
|
||||
|
||||
.PARAMETER IncludeExcludedObjects
|
||||
Show excluded objets. Default disabled
|
||||
|
||||
.PARAMETER Exclusions
|
||||
Provide exclusions for OU's approved by IT. You can provide OU by canonical name or distinguishedName
|
||||
|
||||
.PARAMETER Forest
|
||||
Target different Forest, by default current forest is used
|
||||
|
||||
.PARAMETER ExcludeDomains
|
||||
Exclude domain from search, by default whole forest is scanned
|
||||
|
||||
.PARAMETER IncludeDomains
|
||||
Include only specific domains, by default whole forest is scanned
|
||||
|
||||
.PARAMETER ExtendedForestInformation
|
||||
Ability to provide Forest Information from another command to speed up processing
|
||||
|
||||
.EXAMPLE
|
||||
$Objects = Get-GPOZaurrInheritance -IncludeBlockedObjects -IncludeExcludedObjects -OnlyBlockedInheritance -Exclusions $ExcludedOU
|
||||
$Objects | Format-Table
|
||||
|
||||
.NOTES
|
||||
General notes
|
||||
#>
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[switch] $IncludeBlockedObjects,
|
||||
[switch] $OnlyBlockedInheritance,
|
||||
[switch] $IncludeExcludedObjects,
|
||||
[switch] $IncludeGroupPoliciesForBlockedObjects,
|
||||
[string[]] $Exclusions,
|
||||
|
||||
[alias('ForestName')][string] $Forest,
|
||||
[string[]] $ExcludeDomains,
|
||||
@@ -10,7 +51,11 @@
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation
|
||||
)
|
||||
Begin {
|
||||
$ExclusionsCache = @{}
|
||||
$ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
foreach ($Exclusion in $Exclusions) {
|
||||
$ExclusionsCache[$Exclusion] = $true
|
||||
}
|
||||
}
|
||||
Process {
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
@@ -19,6 +64,37 @@
|
||||
$InheritanceInformation = [Ordered] @{
|
||||
CanonicalName = $OU.canonicalName
|
||||
BlockedInheritance = if ($OU.gpOptions -eq 1) { $true } else { $false }
|
||||
Exclude = $false
|
||||
DomainName = ConvertFrom-DistinguishedName -ToDomainCN -DistinguishedName $OU.DistinguishedName
|
||||
}
|
||||
if ($InheritanceInformation.BlockedInheritance -and $IncludeGroupPoliciesForBlockedObjects.IsPresent) {
|
||||
$GPInheritance = Get-GPInheritance -Target $OU.distinguishedName
|
||||
$ActiveGroupPolicies = foreach ($GPO in $GPInheritance.InheritedGpoLinks) {
|
||||
[PSCustomObject] @{
|
||||
OrganizationalUnit = $OU.canonicalName
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.GpoDomainName
|
||||
LinkedDirectly = if ($OU.DistinguishedName -eq $GPO.Target) { $true } else { $false }
|
||||
GPOID = $GPO.GPOID
|
||||
Enabled = $GPO.Enabled
|
||||
Enforced = $GPO.Enforced
|
||||
Order = $GPO.Order
|
||||
LinkedTo = $GPO.Target
|
||||
OrganizationalUnitDN = $OU.DistinguishedName
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$ActiveGroupPolicies = $null
|
||||
}
|
||||
if ($Exclusions) {
|
||||
if ($ExclusionsCache[$OU.canonicalName]) {
|
||||
$InheritanceInformation['Exclude'] = $true
|
||||
} elseif ($ExclusionsCache[$OU.DistinguishedName]) {
|
||||
$InheritanceInformation['Exclude'] = $true
|
||||
}
|
||||
}
|
||||
if (-not $IncludeExcludedObjects -and $InheritanceInformation['Exclude']) {
|
||||
continue
|
||||
}
|
||||
if (-not $IncludeBlockedObjects) {
|
||||
if ($OnlyBlockedInheritance) {
|
||||
@@ -44,6 +120,8 @@
|
||||
$InheritanceInformation['Computers'] = $null
|
||||
}
|
||||
}
|
||||
$InheritanceInformation['DistinguishedName'] = $OU.DistinguishedName
|
||||
$InheritanceInformation['GroupPolicies'] = $ActiveGroupPolicies
|
||||
if ($OnlyBlockedInheritance) {
|
||||
if ($InheritanceInformation.BlockedInheritance -eq $true) {
|
||||
[PSCustomObject] $InheritanceInformation
|
||||
@@ -52,17 +130,7 @@
|
||||
[PSCustomObject] $InheritanceInformation
|
||||
}
|
||||
}
|
||||
$InheritanceInformation['DistinguishedName'] = $OU.DistinguishedName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
|
||||
$OrganizationalUnits = Get-ADOrganizationalUnit -Filter *
|
||||
$Output = foreach ($OU in $OrganizationalUnits) {
|
||||
Get-GPInheritance -Target $OU.DistinguishedName
|
||||
}
|
||||
$Output | Format-Table
|
||||
#>
|
||||
}
|
||||
+104
-166
@@ -1,13 +1,15 @@
|
||||
function Get-GPOZaurrLink {
|
||||
[cmdletbinding()]
|
||||
[cmdletbinding(DefaultParameterSetName = 'Linked')]
|
||||
param(
|
||||
[parameter(ParameterSetName = 'ADObject', ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Microsoft.ActiveDirectory.Management.ADObject[]] $ADObject,
|
||||
# weirdly enough site doesn't really work this way unless you give it 'CN=Configuration,DC=ad,DC=evotec,DC=xyz' as SearchBase
|
||||
[parameter(ParameterSetName = 'Filter')][string] $Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')",
|
||||
# site doesn't really work this way unless you give it 'CN=Configuration,DC=ad,DC=evotec,DC=xyz' as SearchBase
|
||||
[parameter(ParameterSetName = 'Filter')][string] $Filter, # "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
|
||||
[parameter(ParameterSetName = 'Filter')][string] $SearchBase,
|
||||
[parameter(ParameterSetName = 'Filter')][Microsoft.ActiveDirectory.Management.ADSearchScope] $SearchScope,
|
||||
|
||||
[parameter(ParameterSetName = 'Linked', Mandatory)][validateset('Root', 'DomainControllers', 'Site', 'Other')][string] $Linked,
|
||||
[parameter(ParameterSetName = 'Linked')][validateset('All', 'Root', 'DomainControllers', 'Site', 'OrganizationalUnit')][string[]] $Linked,
|
||||
|
||||
[parameter(ParameterSetName = 'Site')][string[]] $Site,
|
||||
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
@@ -19,30 +21,47 @@
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[switch] $SkipDuplicates,
|
||||
|
||||
[parameter(ParameterSetName = 'Site')]
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[System.Collections.IDictionary] $GPOCache,
|
||||
|
||||
[parameter(ParameterSetName = 'Site')]
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[alias('ForestName')][string] $Forest,
|
||||
|
||||
[parameter(ParameterSetName = 'Site')]
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[string[]] $ExcludeDomains,
|
||||
|
||||
[parameter(ParameterSetName = 'Site')]
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
|
||||
|
||||
[parameter(ParameterSetName = 'Site')]
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation,
|
||||
|
||||
[parameter(ParameterSetName = 'Site')]
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[switch] $AsHashTable,
|
||||
|
||||
[parameter(ParameterSetName = 'Site')]
|
||||
[parameter(ParameterSetName = 'Filter')]
|
||||
[parameter(ParameterSetName = 'ADObject')]
|
||||
[parameter(ParameterSetName = 'Linked')]
|
||||
[switch] $Summary
|
||||
)
|
||||
Begin {
|
||||
$CacheReturnedGPOs = [ordered] @{}
|
||||
@@ -52,6 +71,7 @@
|
||||
# While initially we used $ForestInformation.Domains but the thing is GPOs can be linked to other domains so we need to get them all so we can use cache of it later on even if we're processing just one domain
|
||||
# That's why we use $ForestInformation.Forest.Domains instead
|
||||
foreach ($Domain in $ForestInformation.Forest.Domains) {
|
||||
Write-Verbose "Get-GPOZaurrLink - Building GPO cache for domain $Domain"
|
||||
$QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
|
||||
Get-GPO -All -DomainName $Domain -Server $QueryServer | ForEach-Object {
|
||||
$GPOCache["$Domain$($_.ID.Guid)"] = $_
|
||||
@@ -60,173 +80,91 @@
|
||||
}
|
||||
}
|
||||
Process {
|
||||
if (-not $ADObject) {
|
||||
if ($Linked) {
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
$Splat = @{
|
||||
#Filter = $Filter
|
||||
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
|
||||
# Filter = "(objectClass -eq 'organizationalUnit' -or objectClass -eq 'domainDNS' -or objectClass -eq 'site')"
|
||||
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
|
||||
$getGPOLoopSplat = @{
|
||||
Linked = $Linked
|
||||
ForestInformation = $ForestInformation
|
||||
SearchScope = $SearchScope
|
||||
SearchBase = $SearchBase
|
||||
ADObject = $ADObject
|
||||
Filter = $Filter
|
||||
SkipDuplicates = $SkipDuplicates
|
||||
Site = $Site
|
||||
}
|
||||
Remove-EmptyValue -Hashtable $getGPOLoopSplat -Recursive
|
||||
$getGPOLoopSplat['CacheReturnedGPOs'] = $CacheReturnedGPOs
|
||||
if ($AsHashTable -or $Summary) {
|
||||
$HashTable = [ordered] @{}
|
||||
$SummaryHashtable = [ordered] @{}
|
||||
$Links = Get-GPOZaurrLinkLoop @getGPOLoopSplat
|
||||
foreach ($Link in $Links) {
|
||||
$Key = -join ($Link.DomainName, $Link.GUID)
|
||||
if (-not $HashTable[$Key]) {
|
||||
$HashTable[$Key] = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
}
|
||||
$HashTable[$Key].Add($Link)
|
||||
}
|
||||
foreach ($Key in $HashTable.Keys) {
|
||||
[Array] $Link = $HashTable[$Key]
|
||||
$EnabledLinks = $Link.Enabled.Where( { $_ -eq $true }, 'split')
|
||||
|
||||
$LinkedRoot = $false
|
||||
$LinkedRootPlaces = [System.Collections.Generic.List[string]]::new()
|
||||
$LinkedSite = $false
|
||||
$LinkedSitePlaces = [System.Collections.Generic.List[string]]::new()
|
||||
$LinkedOU = $false
|
||||
$LinkedCrossDomain = $false
|
||||
$LinkedCrossDomainPlaces = [System.Collections.Generic.List[string]]::new()
|
||||
foreach ($InternalLink in $Link) {
|
||||
if ($InternalLink.ObjectClass -eq 'domainDNS') {
|
||||
$LinkedRoot = $true
|
||||
$LinkedRootPlaces.Add($InternalLink.DistinguishedName)
|
||||
} elseif ($InternalLink.ObjectClass -eq 'site') {
|
||||
$LinkedSite = $true
|
||||
$LinkedSitePlaces.Add($InternalLink.Name)
|
||||
} else {
|
||||
$LinkedOU = $true
|
||||
}
|
||||
if ($Linked -contains 'DomainControllers') {
|
||||
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']
|
||||
#if ($SearchBase -notlike "*$DomainDistinguishedName") {
|
||||
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
|
||||
# continue
|
||||
#}
|
||||
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
foreach ($_ in $ADObjectGPO) {
|
||||
$OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache
|
||||
foreach ($OutputGPO in $OutputGPOs) {
|
||||
if (-not $SkipDuplicates) {
|
||||
$OutputGPO
|
||||
} else {
|
||||
$UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid)
|
||||
if (-not $CacheReturnedGPOs[$UniqueGuid]) {
|
||||
$CacheReturnedGPOs[$UniqueGuid] = $OutputGPO
|
||||
$OutputGPO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Linked -contains 'Root') {
|
||||
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
|
||||
#if ($SearchBase -notlike "*$DomainDistinguishedName") {
|
||||
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
|
||||
# continue
|
||||
# }
|
||||
$Splat['Filter'] = "objectClass -eq 'domainDNS'"
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
foreach ($_ in $ADObjectGPO) {
|
||||
$OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache
|
||||
foreach ($OutputGPO in $OutputGPOs) {
|
||||
if (-not $SkipDuplicates) {
|
||||
$OutputGPO
|
||||
} else {
|
||||
$UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid)
|
||||
if (-not $CacheReturnedGPOs[$UniqueGuid]) {
|
||||
$CacheReturnedGPOs[$UniqueGuid] = $OutputGPO
|
||||
$OutputGPO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Linked -contains 'Site') {
|
||||
# Sites are defined only in primary domain
|
||||
if ($ForestInformation['DomainsExtended'][$Domain]['DNSRoot'] -eq $ForestInformation['DomainsExtended'][$Domain]['Forest']) {
|
||||
$SearchBase = -join ("CN=Configuration,", $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName'])
|
||||
# if ($SearchBase -notlike "*$DomainDistinguishedName") {
|
||||
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
|
||||
#continue
|
||||
#}
|
||||
$Splat['Filter'] = "(objectClass -eq 'site')"
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
foreach ($_ in $ADObjectGPO) {
|
||||
Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Linked -contains 'Other') {
|
||||
$SearchBase = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
|
||||
#if ($SearchBase -notlike "*$DomainDistinguishedName") {
|
||||
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
|
||||
# continue
|
||||
#}
|
||||
$Splat['Filter'] = "(objectClass -eq 'organizationalUnit')"
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
foreach ($_ in $ADObjectGPO) {
|
||||
if ($_.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']) {
|
||||
# other skips Domain Root
|
||||
} elseif ($_.DistinguishedName -eq $ForestInformation['DomainsExtended'][$Domain]['DomainControllersContainer']) {
|
||||
# other skips Domain Controllers
|
||||
} else {
|
||||
$OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache
|
||||
foreach ($OutputGPO in $OutputGPOs) {
|
||||
if (-not $SkipDuplicates) {
|
||||
$OutputGPO
|
||||
} else {
|
||||
$UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid)
|
||||
if (-not $CacheReturnedGPOs[$UniqueGuid]) {
|
||||
$CacheReturnedGPOs[$UniqueGuid] = $OutputGPO
|
||||
$OutputGPO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$CN = ConvertFrom-DistinguishedName -ToDomainCN -DistinguishedName $InternalLink.distinguishedName
|
||||
$GPOCN = ConvertFrom-DistinguishedName -ToDomainCN -DistinguishedName $InternalLink.GPODomainDistinguishedName
|
||||
if ($CN -ne $GPOCN) {
|
||||
$LinkedCrossDomain = $true
|
||||
$LinkedCrossDomainPlaces.Add($InternalLink.DistinguishedName)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
$Splat = @{
|
||||
Filter = $Filter
|
||||
Properties = 'distinguishedName', 'gplink', 'CanonicalName'
|
||||
Server = $ForestInformation['QueryServers'][$Domain]['HostName'][0]
|
||||
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey('SearchBase')) {
|
||||
$DomainDistinguishedName = $ForestInformation['DomainsExtended'][$Domain]['DistinguishedName']
|
||||
$SearchBaseDC = ConvertFrom-DistinguishedName -DistinguishedName $SearchBase -ToDC
|
||||
if ($SearchBaseDC -ne $DomainDistinguishedName) {
|
||||
# we check if SearchBase is part of domain distinugishname. If it isn't we skip
|
||||
continue
|
||||
}
|
||||
$Splat['SearchBase'] = $SearchBase
|
||||
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey('SearchScope')) {
|
||||
$Splat['SearchScope'] = $SearchScope
|
||||
}
|
||||
|
||||
try {
|
||||
$ADObjectGPO = Get-ADObject @Splat
|
||||
} catch {
|
||||
Write-Warning "Get-GPOZaurrLink - Get-ADObject error $($_.Exception.Message)"
|
||||
}
|
||||
foreach ($_ in $ADObjectGPO) {
|
||||
$OutputGPOs = Get-PrivGPOZaurrLink -Object $_ -Limited:$Limited.IsPresent -GPOCache $GPOCache
|
||||
foreach ($OutputGPO in $OutputGPOs) {
|
||||
if (-not $SkipDuplicates) {
|
||||
$OutputGPO
|
||||
} else {
|
||||
$UniqueGuid = -join ($OutputGPO.DomainName, $OutputGPO.Guid)
|
||||
if (-not $CacheReturnedGPOs[$UniqueGuid]) {
|
||||
$CacheReturnedGPOs[$UniqueGuid] = $OutputGPO
|
||||
$OutputGPO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($EnabledLinks[0].Count -gt 0) {
|
||||
$IsLinked = $true
|
||||
} else {
|
||||
$IsLinked = $false
|
||||
}
|
||||
$SummaryLink = [PSCustomObject] @{
|
||||
DisplayName = $Link[0].DisplayName
|
||||
DomainName = $Link[0].DomainName
|
||||
GUID = $Link[0].GUID
|
||||
Linked = $IsLinked
|
||||
LinksCount = $Link.Count
|
||||
LinksEnabledCount = $EnabledLinks[0].Count
|
||||
LinksDisabledCount = $EnabledLinks[1].Count
|
||||
LinkedCrossDomain = $LinkedCrossDomain
|
||||
LinkedRoot = $LinkedRoot
|
||||
LinkedSite = $LinkedSite
|
||||
LinkedOU = $LinkedOU
|
||||
LinkedSitePlaces = $LinkedSitePlaces
|
||||
LinkedRootPlaces = $LinkedRootPlaces
|
||||
LinkedCrossDomainPlaces = $LinkedCrossDomainPlaces
|
||||
Links = $Link.DistinguishedName
|
||||
LinksObjects = $Link
|
||||
}
|
||||
$SummaryHashtable[$Key] = $SummaryLink
|
||||
}
|
||||
if ($AsHashTable -and $Summary) {
|
||||
$SummaryHashtable
|
||||
} elseif ($AsHashTable) {
|
||||
$HashTable
|
||||
} elseif ($Summary) {
|
||||
$SummaryHashtable.Values
|
||||
}
|
||||
} else {
|
||||
foreach ($Object in $ADObject) {
|
||||
Get-PrivGPOZaurrLink -Object $Object -Limited:$Limited.IsPresent -GPOCache $GPOCache
|
||||
}
|
||||
Get-GPOZaurrLinkLoop @getGPOLoopSplat
|
||||
}
|
||||
}
|
||||
End {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
$CacheSummaryLinks = [ordered] @{} # cache
|
||||
|
||||
# Get all links
|
||||
$Links = Get-GPOZaurrLink -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
$Links = Get-GPOZaurrLink -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation -Linked Root, DomainControllers, OrganizationalUnit
|
||||
foreach ($Link in $Links) {
|
||||
if (-not $CacheSummaryLinks["$($Link.DomainName)$($Link.Guid)"]) {
|
||||
$CacheSummaryLinks["$($Link.DomainName)$($Link.Guid)"] = [System.Collections.Generic.List[System.Object]]::new()
|
||||
@@ -121,13 +121,13 @@
|
||||
for ($i = 0; $i -le $HighestCount; $i++) {
|
||||
"Level$i"
|
||||
}
|
||||
'Owner'
|
||||
'GpoStatus'
|
||||
'Description'
|
||||
'CreationTime'
|
||||
'ModificationTime'
|
||||
'GPODomainDistinguishedName'
|
||||
'GPODistinguishedName'
|
||||
#'Owner'
|
||||
#'GpoStatus'
|
||||
#'Description'
|
||||
#'CreationTime'
|
||||
#'ModificationTime'
|
||||
#'GPODomainDistinguishedName'
|
||||
#'GPODistinguishedName'
|
||||
)
|
||||
$ReturnObject.MultipleLinks = $ReturnObject.MultipleLinks | Select-Object -Property $Properties
|
||||
}
|
||||
|
||||
@@ -26,13 +26,13 @@
|
||||
} 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
|
||||
$IdentityOwnerAdvanced = Get-WinADObject -Identity $ACL.Owner -Cache -Verbose:$false
|
||||
#} else {
|
||||
# $IdentityOwner = [PSCustomObject] @{ SID = ''; Type = 'Unknown' }
|
||||
# $IdentityOwnerAdvanced = [PSCustomObject] @{ ObjectClass = '' }
|
||||
#}
|
||||
if ($ACL.Owner) {
|
||||
$IdentityOwner = Convert-Identity -Identity $ACL.Owner -Verbose:$false
|
||||
$IdentityOwnerAdvanced = Get-WinADObject -Identity $ACL.Owner -Cache -Verbose:$false
|
||||
} else {
|
||||
$IdentityOwner = [PSCustomObject] @{ Name = ''; SID = ''; Type = 'Unknown' }
|
||||
$IdentityOwnerAdvanced = [PSCustomObject] @{ ObjectClass = '' }
|
||||
}
|
||||
if (-not $OwnerOnly) {
|
||||
if (-not $SkipOwner) {
|
||||
if ($IdentityOwner.SID -eq "S-1-5-32-544") {
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
function Get-GPOZaurrOrganizationalUnit {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[alias('ForestName')][string] $Forest,
|
||||
[string[]] $ExcludeDomains,
|
||||
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
|
||||
[System.Collections.IDictionary] $ExtendedForestInformation,
|
||||
|
||||
[ValidateSet('OK', 'Unlink', 'Delete')][string[]] $Option,
|
||||
[alias('ExcludeOU', 'Exclusions')][string[]] $ExcludeOrganizationalUnit
|
||||
)
|
||||
$CachedOu = [ordered] @{}
|
||||
$CachedGPO = [ordered] @{}
|
||||
|
||||
$ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
$GroupPolicies = Get-GPOZaurrAD -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation
|
||||
foreach ($GPO in $GroupPolicies) {
|
||||
$CachedGPO[$GPO.GPODistinguishedName] = $GPO
|
||||
}
|
||||
foreach ($Domain in $ForestInformation.Domains) {
|
||||
Write-Verbose "Get-GPOZaurrOrganizationalUnit - Processing $($Domain)"
|
||||
$CountTop = 0
|
||||
$TopOrganizationalUnits = Get-ADOrganizationalUnit -Filter * -Properties LinkedGroupPolicyObjects, DistinguishedName, ntSecurityDescriptor -Server $ForestInformation['QueryServers'][$Domain]['hostname'][0] -SearchScope OneLevel
|
||||
foreach ($TopOU in $TopOrganizationalUnits) {
|
||||
$CountTop++
|
||||
Write-Verbose "Get-GPOZaurrOrganizationalUnit - Processing $($Domain) / $($TOPOU.DistinguishedName) [$CountTop/$($TopOrganizationalUnits.Count)]"
|
||||
# cache top ou
|
||||
if ($TopOU.LinkedGroupPolicyObjects) {
|
||||
$LinkedGPOs = $CachedGPO[$TopOU.LinkedGroupPolicyObjects]
|
||||
} else {
|
||||
$LinkedGPOs = $null
|
||||
}
|
||||
$CachedOu[$TopOU.DistinguishedName] = [ordered]@{
|
||||
'LinkedGroupPolicyObjects' = $TopOU.LinkedGroupPolicyObjects
|
||||
'LinkedGroupPolicy' = $LinkedGPOs
|
||||
'Objects' = [ordered] @{}
|
||||
'ObjectsClasses' = [ordered] @{}
|
||||
'ObjectsCountDirect' = 0
|
||||
'ObjectsCountIndirect' = 0
|
||||
'ObjectsCountTotal' = 0
|
||||
'Level' = 'Top'
|
||||
'Domain' = $Domain
|
||||
}
|
||||
|
||||
# cache children OUs
|
||||
$OUs = Get-ADOrganizationalUnit -SearchScope Subtree -SearchBase $TopOU.DistinguishedName -Server $ForestInformation['QueryServers'][$Domain]['hostname'][0] -Properties LinkedGroupPolicyObjects, DistinguishedName -Filter *
|
||||
Write-Verbose "Get-GPOZaurrOrganizationalUnit - Processing $($Domain) / $($TOPOU.DistinguishedName) [$CountTop/$($TopOrganizationalUnits.Count)], found $($OUs.Count) OU's to process."
|
||||
foreach ($OU in $OUs) {
|
||||
if (-not $CachedOu[$OU.DistinguishedName]) {
|
||||
if ($OU.LinkedGroupPolicyObjects) {
|
||||
$LinkedGPOs = $CachedGPO[$OU.LinkedGroupPolicyObjects]
|
||||
} else {
|
||||
$LinkedGPOs = $null
|
||||
}
|
||||
$CachedOu[$OU.DistinguishedName] = [ordered]@{
|
||||
'LinkedGroupPolicyObjects' = $OU.LinkedGroupPolicyObjects
|
||||
'LinkedGroupPolicy' = $LinkedGPOs
|
||||
'Objects' = [ordered] @{}
|
||||
'ObjectsClasses' = [ordered] @{}
|
||||
'ObjectsCountDirect' = 0
|
||||
'ObjectsCountIndirect' = 0
|
||||
'ObjectsCountTotal' = 0
|
||||
'Level' = 'Child'
|
||||
'Domain' = $Domain
|
||||
}
|
||||
}
|
||||
}
|
||||
# Find all objects in those OUs
|
||||
$ObjectsInOu = Get-ADObject -LDAPFilter "(|(ObjectClass=user)(ObjectClass=contact)(ObjectClass=computer)(ObjectClass=group)(objectClass=inetOrgPerson))" -SearchBase $TopOU.distinguishedName -Server $ForestInformation['QueryServers'][$Domain]['hostname'][0]
|
||||
Write-Verbose "Get-GPOZaurrOrganizationalUnit - Processing $($Domain) / $($TOPOU.DistinguishedName) [$CountTop/$($TopOrganizationalUnits.Count)], found $($ObjectsInOu.Count) objects to process."
|
||||
foreach ($Object in $ObjectsInOu) {
|
||||
$Place = ConvertFrom-DistinguishedName -ToOrganizationalUnit -DistinguishedName $Object.DistinguishedName
|
||||
$AllOUs = ConvertFrom-DistinguishedName -ToMultipleOrganizationalUnit -IncludeParent -DistinguishedName $Place
|
||||
foreach ($OU in $AllOUs) {
|
||||
if ($OU -eq $Place) {
|
||||
$CachedOu[$OU]['Objects'][$Object.DistinguishedName] = $Object
|
||||
$CachedOu[$OU]['ObjectsClasses'][$Object.ObjectClass] = ''
|
||||
$CachedOu[$OU]['ObjectsCountDirect']++
|
||||
} else {
|
||||
$CachedOu[$OU]['ObjectsClasses'][$Object.ObjectClass] = ''
|
||||
$CachedOu[$OU]['ObjectsCountIndirect']++
|
||||
}
|
||||
$CachedOu[$OU]['ObjectsCountTotal']++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($OU in $CachedOu.Keys) {
|
||||
$ObjectClasses = [string[]] $CachedOu[$OU]['ObjectsClasses'].Keys
|
||||
|
||||
if ($CachedOu[$OU]['ObjectsCountTotal'] -eq 0 -and $CachedOu[$OU]['LinkedGroupPolicyObjects'].Count -gt 0) {
|
||||
$Status = "Unlink GPO", 'Delete OU'
|
||||
} elseif ($CachedOu[$OU]['ObjectsCountTotal'] -eq 0 -and $CachedOu[$OU]['LinkedGroupPolicyObjects'].Count -eq 0) {
|
||||
$Status = 'Delete OU'
|
||||
} elseif ($CachedOU[$Ou]['ObjectsCountTotal'] -gt 0 -and $CachedOu[$OU]['LinkedGroupPolicyObjects'].Count -gt 0 -and $ObjectClasses -notcontains 'User' -and $ObjectClasses -notcontains 'Computer' ) {
|
||||
$Status = "Unlink GPO"
|
||||
} else {
|
||||
$Status = 'OK'
|
||||
}
|
||||
|
||||
if ($Option) {
|
||||
$Found = $false
|
||||
if ($Option -contains 'Ok' -and $Status -contains 'OK') {
|
||||
$Found = $true
|
||||
} elseif ($Option -contains 'Unlink' -and $Status -contains 'Unlink GPO') {
|
||||
$Found = $true
|
||||
} elseif ($Option -contains 'Delete' -and $Status -contains 'Delete OU') {
|
||||
$Found = $true
|
||||
}
|
||||
if ($ExcludeOrganizationalUnit) {
|
||||
foreach ($ExcludedOU in $ExcludeOrganizationalUnit) {
|
||||
if ($OU -like $ExcludedOU) {
|
||||
$Found = $false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-not $Found) {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if ($ExcludeOrganizationalUnit) {
|
||||
foreach ($ExcludedOU in $ExcludeOrganizationalUnit) {
|
||||
if ($OU -like $ExcludedOU) {
|
||||
$Status = 'Excluded'
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[PSCustomObject] @{
|
||||
Organizationalunit = $OU
|
||||
Level = $CachedOu[$OU]['Level']
|
||||
DomainName = $CachedOu[$OU]['Domain']
|
||||
Status = $Status
|
||||
GPOCount = $CachedOu[$OU]['LinkedGroupPolicyObjects'].Count
|
||||
ObjectCountDirect = $CachedOu[$OU]['ObjectsCountDirect']
|
||||
ObjectCountIndirect = $CachedOu[$OU]['ObjectsCountIndirect']
|
||||
ObjectCountTotal = $CachedOu[$OU]['ObjectsCountTotal']
|
||||
ObjectClasses = $ObjectClasses
|
||||
GPONames = $CachedOu[$OU]['LinkedGroupPolicy'].DisplayName
|
||||
Objects = $CachedOu[$OU]['Objects'].Values.Name
|
||||
GPO = $CachedOu[$OU]['LinkedGroupPolicy']
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user