Compare commits

...

30 Commits

Author SHA1 Message Date
Przemyslaw Klys 9c689708ba Report improvement 2021-08-06 11:36:30 +02:00
Przemyslaw Klys bb18d488b4 Example improvements 2021-08-06 11:36:22 +02:00
Przemyslaw Klys e72d81aee3 Example update 2021-08-05 23:56:35 +02:00
Przemyslaw Klys 70ed52cdf9 Improvement to report 2021-08-05 23:56:27 +02:00
Przemyslaw Klys 3b414e712c Example update 2021-08-05 23:33:35 +02:00
Przemyslaw Klys 7ed1410fd9 Parameter sets update 2021-08-05 23:26:07 +02:00
Przemyslaw Klys 6d2e476916 Changelog update 2021-08-05 23:26:00 +02:00
Przemyslaw Klys b7ed5e0c5a Added examples for new functions 2021-08-05 22:13:56 +02:00
Przemyslaw Klys 72bd69d0e6 Update changelog 2021-08-05 22:09:28 +02:00
Przemyslaw Klys b5c1f3dcd5 Improved Get-GPOZaurrOrganizationalUnit 2021-08-05 22:09:09 +02:00
Przemyslaw Klys bc773e2e83 Added Remove-GPOZaurrLinkEmptyOU 2021-08-05 22:08:56 +02:00
Przemyslaw Klys 8db961cba6 Improve report 2021-08-05 22:08:46 +02:00
Przemyslaw Klys 227639d0f6 New functions added in psd1 2021-08-05 22:08:22 +02:00
Przemyslaw Klys e03f819461 Update PSD1 2021-08-03 19:41:38 +02:00
Przemyslaw Klys fb955f645b Add changelog 2021-08-03 19:41:30 +02:00
Przemyslaw Klys 3fc3b74798 Added Get-GPOZaurrOrganizationalUnit 2021-08-03 19:40:41 +02:00
Przemyslaw Klys 695f4dbe6a Twitter complainer 2021-07-08 20:16:01 +02:00
Przemyslaw Klys 5d69cef128 changelog update 2021-05-26 22:53:30 +02:00
Przemyslaw Klys 062374b4be Update readme, PSD1 2021-05-26 22:53:10 +02:00
Przemyslaw Klys e61329ac66 Improved certificates 2021-05-26 16:32:07 +02:00
Przemyslaw Klys d3328dbb81 Readme update 2021-05-17 23:22:11 +02:00
Przemyslaw Klys 5803371b5e Update PSD1 2021-05-17 23:14:37 +02:00
Przemyslaw Klys 263f364ede PSM1 update 2021-05-17 23:14:30 +02:00
Przemyslaw Klys 16a181155b Potentially fixes #17 2021-05-17 23:14:16 +02:00
Przemyslaw Klys 962d8829d7 PSD1 update 2021-04-15 18:44:15 +02:00
Przemyslaw Klys 4155c35cc6 Moved description a bit 2021-04-15 18:43:47 +02:00
Przemyslaw Klys 614d8cbda5 PSD1/Readme release 2021-04-12 08:46:35 +02:00
Przemyslaw Klys 43e7f2e746 Dont auto replace words 🐛 2021-04-12 08:45:35 +02:00
Przemyslaw Klys 9a3ed3b6ce Added hidding column 2021-04-12 00:09:47 +02:00
Przemyslaw Klys 50f0cfc1a6 Improved blocked inheritance 2021-04-11 21:36:40 +02:00
17 changed files with 589 additions and 26 deletions
+4 -1
View File
@@ -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,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,5 @@
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
#Get-GPOZaurrOrganizationalUnit -Verbose -Option Unlink | Format-Table
Invoke-GPOZaurr -Type GPOOrganizationalUnit -Online -FilePath $PSScriptRoot\Reports\GPOZaurrOU.html
+5 -5
View File
@@ -6,9 +6,9 @@
CompatiblePSEditions = @('Desktop')
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-GPOZaurrBrokenLink', '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-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-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrBrokenLink', 'Repair-GPOZaurrNetLogonOwner', 'Repair-GPOZaurrPermission', '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.125'
ModuleVersion = '0.0.129'
PowerShellVersion = '5.1'
PrivateData = @{
PSData = @{
@@ -18,15 +18,15 @@
}
}
RequiredModules = @(@{
ModuleVersion = '0.0.198'
ModuleVersion = '0.0.208'
ModuleName = 'PSSharedGoods'
Guid = 'ee272aa8-baaa-4edf-9f45-b6d6f7d844fe'
}, @{
ModuleVersion = '0.0.124'
ModuleVersion = '0.0.130'
ModuleName = 'ADEssentials'
Guid = '9fc9fd61-7f11-4f4b-a527-084086f1905f'
}, @{
ModuleVersion = '0.0.148'
ModuleVersion = '0.0.158'
ModuleName = 'PSWriteHTML'
Guid = 'a7bdf640-f5cb-4acf-9de0-365b322d245c'
}, 'CimCmdlets', 'Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Utility', 'Microsoft.PowerShell.Security')
+46 -6
View File
@@ -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 '*'
+101
View File
@@ -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 -1
View File
@@ -290,6 +290,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
@@ -315,7 +316,6 @@
'UserSettingsVersionIdentical' = if ($XMLContent.GPO.User.VersionDirectory -eq $XMLContent.GPO.User.VersionSysvol) { $true } else { $false }
'UserSettings' = $XMLContent.GPO.User.ExtensionData.Extension
'NoSettings' = $NoSettings
'Description' = $GPO.Description
'CreationTime' = [DateTime] $XMLContent.GPO.CreatedTime
'ModificationTime' = [DateTime] $XMLContent.GPO.ModifiedTime
'ReadTime' = [DateTime] $XMLContent.GPO.ReadTime
+10 -9
View File
@@ -75,7 +75,7 @@
"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 "Block Inheritance" -FontSize 10pt -FontWeight bold
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. "
@@ -85,10 +85,10 @@
New-HTMLText -Text @(
'As it stands currently there are ',
$Script:Reporting['GPOBlockedInheritance']['Data'].Count,
' organiational units with '
' organisational units with '
'GPO Inheritance Block'
' out of which '
$Script:Reporting['GPOBlockedInheritance']['Variables']['Exclude'].Count,
$Script:Reporting['GPOBlockedInheritance']['Variables']['Exclude'],
' are marked as Excluded '
'(approved by IT). '
) -FontSize 10pt -FontWeight normal, bold, normal, bold, normal, bold, normal, bold -LineBreak
@@ -96,9 +96,9 @@
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/Exclude, 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/Exclude, 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
@@ -118,7 +118,7 @@
}
New-HTMLPanel {
New-HTMLChart {
New-ChartLegend -Names 'Affected', 'Affected, but Exclude' -Color Salmon, PaleGreen
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']
@@ -137,14 +137,15 @@
New-TableCondition -Name 'UsersCount' -Value 0
New-TableCondition -Name 'ComputersCount' -Value 0
} -BackgroundColor Salmon -FailBackgroundColor Amber -HighlightHeaders 'UsersCount', 'ComputersCount'
} -PagingOptions 10, 20, 30, 40, 50 -SearchBuilder -ExcludeProperty GroupPolicies
New-TableColumnOption -Hidden $true -ColumnIndex 8
} -PagingOptions 5, 10, 20, 30, 40, 50 -SearchBuilder -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 10, 20, 30, 40, 50 -SearchBuilder -ExcludeProperty GroupPolicies -DataTableID 'TableWithGroupPoliciesBlockedInheritance'
} -PagingOptions 5, 10, 20, 30, 40, 50 -SearchBuilder -DataTableID 'TableWithGroupPoliciesBlockedInheritance'
}
if ($Script:Reporting['Settings']['HideSteps'] -eq $false) {
New-HTMLSection -Name 'Steps to fix - Organizational Units with Group Policy Blocked Inheritance' {
@@ -174,7 +175,7 @@
}
New-HTMLText -Text "Alternatively if you prefer working with console you can run: "
New-HTMLCodeBlock -Code {
$GPOOutput = Get-GPOZaurrInheritance -IncludeBlockedObjects -IncludeExcludeObjects -OnlyBlockedInheritance
$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."
@@ -0,0 +1,208 @@
$GPOZaurrOrganizationalUnit = [ordered] @{
Name = 'Group Policy Organizational Units'
Enabled = $true
ActionRequired = $null
Data = $null
Execute = {
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']['UnlinkGPODeleteOU']++
$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]++
} 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
UnlinkGPODeleteOU = 0
DeleteOU = 0
Legitimate = 0
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 and OU removed (be careful!) (no objects): ', $Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPODeleteOU'] -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
New-HTMLText -Text @(
"Please make sure that you really want to unlink GPO or delete Organizational Unit before executing changes. Sometimes it's completly valid to keep one or the other. "
"Unlinking GPO from OU that has no Computer or User objects is fairly safe exercise. Removing OU requires a bit more dive in, and should only be executed if you know what you're doing. "
) -FontWeight normal, bold -Color None, Red -FontSize 10pt
}
Solution = {
New-HTMLSection -Invisible {
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']['UnlinkGPODeleteOU']))" -Value $Script:Reporting['GPOOrganizationalUnit']['Variables']['UnlinkGPODeleteOU']
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
} -PagingOptions 10, 20, 30, 40, 50 -SearchBuilder -ExcludeProperty GPO
}
if ($Script:Reporting['Settings']['HideSteps'] -eq $false) {
New-HTMLSection -Name 'Steps to fix Group Organizational Units' {
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."
}
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 -1
View File
@@ -99,7 +99,7 @@
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 assed due to permissions issue: ", $Script:Reporting['GPOBroken']['Variables']['NotAvailablePermissionIssue'] -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 {
+1
View File
@@ -4,6 +4,7 @@
GPOOwners = $GPOZaurrOwners
GPOConsistency = $GPOZaurrConsistency
GPODuplicates = $GPOZaurrDuplicates
GPOOrganizationalUnit = $GPOZaurrOrganizationalUnit
GPOList = $GPOZaurrList
GPOLinks = $GPOZaurrLinks
GPOPassword = $GPOZaurrPassword
+2 -2
View File
@@ -789,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
}
}
<#
+130
View File
@@ -0,0 +1,130 @@
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
)
$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 (-not $Found) {
continue
}
}
[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']
}
}
}
+3 -1
View File
@@ -212,7 +212,9 @@
$DisplayProperties = @(
$FirstProperties
foreach ($Property in $Properties) {
$Property
if ($Property -notin $FirstProperties -and $Property -notin $EndProperties) {
$Property
}
}
$EndProperties
)
+38
View File
@@ -0,0 +1,38 @@
function Remove-GPOZaurrLinkEmptyOU {
[cmdletbinding(SupportsShouldProcess)]
param(
[alias('ForestName')][string] $Forest,
[string[]] $ExcludeDomains,
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
[System.Collections.IDictionary] $ExtendedForestInformation,
[string[]] $ExcludeOrganizationalUnit,
[int] $LimitProcessing = [int32]::MaxValue
)
$Processed = 0
$OrganizationalUnits = Get-GPOZaurrOrganizationalUnit -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation -Option Unlink
foreach ($OU in $OrganizationalUnits) {
if ($OU.Status -contains 'Unlink GPO') {
if ($OU.OrganizationalUnit -in $ExcludeOrganizationalUnit) {
Write-Verbose "Remove-GPOZaurrLinkEmptyOU - Processing $($OU.Organizationalunit) was skipped as it's excluded."
continue
}
Write-Verbose "Remove-GPOZaurrLinkEmptyOU - Processing $($OU.Organizationalunit) found OU with GPOs to unlink"
$Processed++
foreach ($GPO in $OU.GPO) {
Write-Verbose "Remove-GPOZaurrLinkEmptyOU - Removing $($GPO.DisplayName) link from $($OU.Organizationalunit)"
try {
Remove-GPLink -ErrorAction Stop -Guid $GPO.GUID -Domain $GPO.DomainName -Target $OU.Organizationalunit
} catch {
Write-Warning "Remove-GPOZaurrLinkEmptyOU - Error removing link of $($GPO.DisplayName) from $($OU.OrganizationalUnit) error: $($_.Exception.Message)"
}
}
if ($Processed -ge $LimitProcessing) {
Write-Verbose "Remove-GPOZaurrLinkEmptyOU - Limit processing hit, stopping."
break
}
}
}
}
+8
View File
@@ -38,6 +38,9 @@
.PARAMETER LimitProcessing
Allows to specify maximum number of items that will be fixed in a single run. It doesn't affect amount of GPOs processed
.PARAMETER Force
Pushes new owner regardless if it's already set or not
.EXAMPLE
Set-GPOZaurrOwner -Type All -Verbose -WhatIf -LimitProcessing 2
@@ -72,11 +75,16 @@
[Parameter(ParameterSetName = 'Named')]
[string] $Principal,
[Parameter(ParameterSetName = 'Type')]
[Parameter(ParameterSetName = 'Named')]
[switch] $SkipSysvol,
[Parameter(ParameterSetName = 'Type')]
[Parameter(ParameterSetName = 'Named')]
[int] $LimitProcessing = [int32]::MaxValue,
[Parameter(ParameterSetName = 'Type')]
[Parameter(ParameterSetName = 'Named')]
[switch] $Force
)
Begin {
+16
View File
@@ -55,6 +55,22 @@ To understand the usage I've created blog post you may find useful
## Changelog
- 0.0.129
- Added `Get-GPOZaurrOrganizationalUnit` and added `GPOOrganizationalUnit` in `Invoke-GPOZaurr` (preview)
- Added `Remove-GPOZaurrLinkEmptyOU` which allows removing links from Empty OUs (preview)
- Small update to parameter sets for `Set-GPOZaurrOwner`
- 0.0.128 - 2021.05.26
- ☑ Improved `Invoke-GPOZaurrContent` - type `PublicKeyPoliciesCertificates` - added more certificate information
- ☑ Improved `Invoke-GPOZaurr` - type `GPOAnalysis` - added more certificate information
- 0.0.128 Alpha 1 - 2021.05.17
- 🐛 Fixes errors when normalizing properties [#17](https://github.com/EvotecIT/GPOZaurr/issues/17)
- 0.0.127 - 2021.04.15
- ☑ Improved `Invoke-GPOZaurr`
- ☑ Report `GPOList` - moved description closer to statuses
- ☑ Improved `Get-GPOZaurr` - moved description closer to statuses
- 0.0.126 - 2021.04.12
- ☑ Improved `Invoke-GPOZaurr`
- ☑ Report `GPOBlockedInheritance` - hidden DistinguishedName, fixed some small typos
- 0.0.125 - 2021.04.11
- ☑ Improved `Invoke-GPOZaurr`
- ☑ Report `GPOBlockedInheritance` - small fixes