Compare commits

..

68 Commits

Author SHA1 Message Date
Przemyslaw Klys 37483c91b5 Update PSD1 2021-02-10 19:51:17 +01:00
Przemyslaw Klys 9172948be3 Added folder redirection #12 2021-02-10 19:50:45 +01:00
Przemyslaw Klys 14567959f7 #12 2021-02-10 19:49:51 +01:00
Przemyslaw Klys 6a9ad14083 Modified readme 2021-02-10 19:25:10 +01:00
Przemyslaw Klys e00de40cd2 Adds description #13 2021-02-10 19:24:04 +01:00
Przemyslaw Klys 6f806698e9 update readme 2021-02-10 12:02:01 +01:00
Przemyslaw Klys 2e1571b0d7 Update 2021-02-10 11:56:31 +01:00
Przemyslaw Klys ffedd2d9d2 Update 2021-02-10 11:56:23 +01:00
Przemyslaw Klys 911bc50f22 Update readme 2021-02-10 11:00:52 +01:00
Przemyslaw Klys 0383d249e9 PSD1 update 2021-02-10 10:57:12 +01:00
Przemyslaw Klys 8070179d27 Update readme 2021-02-10 10:56:48 +01:00
Przemyslaw Klys db67e6191e Improved false-positive detection for Empty on non-english systesm 2021-02-10 10:47:23 +01:00
Przemyslaw Klys db9b6d60c6 PSD1 update 2021-02-09 18:07:24 +01:00
Przemyslaw Klys 2c965d81d5 Small update 2021-02-09 18:01:48 +01:00
Przemyslaw Klys bff372affe Update readme 2021-02-09 17:58:06 +01:00
Przemyslaw Klys 138a0f411e Added information about filepath 2021-02-09 17:56:56 +01:00
Przemyslaw Klys 1c37a9d1df Update readme / PSD1 2021-02-09 10:58:02 +01:00
Przemyslaw Klys 30535c1baf Update readme 2021-02-09 10:55:23 +01:00
Przemyslaw Klys 56c722edd0 Small fix to exclude GPOList.xml 2021-02-09 10:54:43 +01:00
Przemyslaw Klys 1f43ae21fe PSD1 update 2021-02-08 17:43:40 +01:00
Przemyslaw Klys ef90ef05f7 Update readme 2021-02-08 17:43:13 +01:00
Przemyslaw Klys 43b304d252 Removed redundant code
Handles ObjectClass problem properly now
2021-02-08 17:43:07 +01:00
Przemyslaw Klys 24e691edb9 Update PSD1/readme 2021-02-07 15:08:54 +01:00
Przemyslaw Klys 1c787735d4 update readme 2021-02-07 10:08:36 +01:00
Przemyslaw Klys 13a2aa6482 Missing text added 2021-02-07 10:08:29 +01:00
Przemyslaw Klys 1ac1f83abd Fix #9 2021-02-07 10:06:11 +01:00
Przemyslaw Klys 65b2867588 Update readme 2021-02-04 18:43:10 +01:00
Przemyslaw Klys 1043a2d512 update list 2021-02-04 18:37:36 +01:00
Przemyslaw Klys 7002813027 PSD1 update 2021-01-27 19:09:28 +01:00
Przemyslaw Klys 03b8e4f2cb Update readme 2021-01-27 19:09:02 +01:00
Przemyslaw Klys 680762733e Update to Online 2021-01-27 19:08:54 +01:00
Przemyslaw Klys 7a37d5b9f6 Added Online switch 2021-01-27 18:59:06 +01:00
Przemyslaw Klys a1e9a4a3fa PSD1 update 2021-01-25 21:25:05 +01:00
Przemyslaw Klys 8cbb3272b2 Update readme 2021-01-25 21:24:40 +01:00
Przemyslaw Klys 8da0c1793d Added WindowsTimeService #6 2021-01-25 21:23:19 +01:00
Przemyslaw Klys 5a7b20ca2b Update examples 2021-01-25 19:46:15 +01:00
Przemyslaw Klys ebffba3b95 Update readme 2021-01-25 19:43:33 +01:00
Przemyslaw Klys a79071c395 PSD1 update 2021-01-25 19:43:02 +01:00
Przemyslaw Klys a5a889b468 Small update to docs 2021-01-25 19:42:36 +01:00
Przemyslaw Klys 62d73041ea Update readme 2021-01-24 17:56:37 +01:00
Przemyslaw Klys d88307047c PSD1 update 2021-01-24 17:53:34 +01:00
Przemyslaw Klys 7d85d41747 Text improvement 2021-01-24 16:48:37 +01:00
Przemyslaw Klys a1fab2ceb2 Text improvement 2021-01-24 10:28:35 +01:00
Przemyslaw Klys 99f07f61e3 Text improvement 2021-01-24 10:28:29 +01:00
Przemyslaw Klys 58136f0c43 Update psd1 2021-01-22 12:40:45 +01:00
Przemyslaw Klys b55729d8e0 Update deployment module 2021-01-22 12:40:36 +01:00
Przemyslaw Klys 6206a33a2e Update readme 2021-01-22 12:40:27 +01:00
Przemyslaw Klys 165381b1e3 Small update 2021-01-22 12:39:53 +01:00
Przemyslaw Klys ea1de10fd9 Update readme 2021-01-11 10:30:41 +01:00
Przemyslaw Klys 03453b6bdb PSD1 update 2021-01-11 10:27:41 +01:00
Przemyslaw Klys 4d7f49902d Update 2021-01-11 10:27:34 +01:00
Przemyslaw Klys 508d778d06 Update consistency report 2021-01-11 10:14:01 +01:00
Przemyslaw Klys 5c3157f15f Update psd1 2021-01-11 10:13:54 +01:00
Przemyslaw Klys b33f42b320 Update readme 2021-01-11 10:13:48 +01:00
Przemyslaw Klys f8d3b363e7 Update list 2021-01-11 09:52:59 +01:00
Przemyslaw Klys a68d917d19 Small test 2021-01-11 09:51:10 +01:00
Przemyslaw Klys 946bb3029f Update 2021-01-11 09:51:04 +01:00
Przemyslaw Klys 975bf5b889 Update PSD1 2021-01-11 09:00:13 +01:00
Przemyslaw Klys 6fa0818375 Update Examples 2021-01-11 08:59:35 +01:00
Przemyslaw Klys 2abec9579a Update Invoke-GPOZaurrContent 2021-01-11 08:58:51 +01:00
Przemyslaw Klys 75a8083368 Update PSD1/Readme 2021-01-11 08:58:24 +01:00
Przemyslaw Klys 06c711694e Update readme/psd1 2021-01-05 13:32:57 +01:00
Przemyslaw Klys 8a38ac4556 Improved report 2021-01-05 13:31:45 +01:00
Przemyslaw Klys 9d2ae288c0 Update PSD1/Readme 2021-01-04 21:47:54 +01:00
Przemyslaw Klys 0bc50328ee solves issue when gpLink is empty 2021-01-04 21:47:26 +01:00
Przemyslaw Klys a74b662c9b Prevent errors from doing harm 2021-01-04 21:29:57 +01:00
Przemyslaw Klys 37d8db92f7 Update to make sure it works properly for domains 2021-01-04 21:15:49 +01:00
Przemyslaw Klys d094344f9f Update docs 2021-01-04 21:15:28 +01:00
32 changed files with 489 additions and 163 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
Get-GPOZaurrLink | Format-Table -AutoSize *
Get-GPOZaurrLink -Verbose | Format-Table -AutoSize *
+1 -1
View File
@@ -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 -Type LocalGroups
$Output | Format-Table
+2 -2
View File
@@ -1,4 +1,4 @@
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
#$Output = Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -PassThru -Type GPOConsistency, GPOList, GPODuplicates, GPOOrphans, GPOOwners, NetLogonOwners, GPOPermissionsRead, GPOPermissionsAdministrative,GPOPermissionsUnknown
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type GPOPermissions,GPOPermissionsRead
#$Output = Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -PassThru -Type GPOConsistency, GPOList, GPODuplicates, GPOBroken, GPOOwners, NetLogonOwners, GPOPermissionsRead, GPOPermissionsAdministrative,GPOPermissionsUnknown
Invoke-GPOZaurr #-FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type GPOList
+1 -1
View File
@@ -1,3 +1,3 @@
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type GPOConsistency, GPOList, GPODuplicates, GPOOrphans, GPOOwners, NetLogonOwners, GPOPermissionsRead, GPOPermissionsAdministrative, GPOPermissionsUnknown, GPOPermissions
Invoke-GPOZaurr -FilePath $PSScriptRoot\Reports\GPOZaurr.html -Type GPOConsistency, GPOList, GPODuplicates, GPOBroken, GPOOwners, NetLogonOwners, GPOPermissionsRead, GPOPermissionsAdministrative, GPOPermissionsUnknown, GPOPermissions
+1 -1
View File
@@ -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 = 'GPOBroken'; 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,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
+4 -4
View File
@@ -8,7 +8,7 @@
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')
GUID = 'f7d4c9e4-0298-4f51-ad77-e8e3febebbde'
ModuleVersion = '0.0.103'
ModuleVersion = '0.0.121'
PowerShellVersion = '5.1'
PrivateData = @{
PSData = @{
@@ -18,15 +18,15 @@
}
}
RequiredModules = @(@{
ModuleVersion = '0.0.192'
ModuleVersion = '0.0.195'
ModuleName = 'PSSharedGoods'
Guid = 'ee272aa8-baaa-4edf-9f45-b6d6f7d844fe'
}, @{
ModuleVersion = '0.0.103'
ModuleVersion = '0.0.112'
ModuleName = 'ADEssentials'
Guid = '9fc9fd61-7f11-4f4b-a527-084086f1905f'
}, @{
ModuleVersion = '0.0.122'
ModuleVersion = '0.0.132'
ModuleName = 'PSWriteHTML'
Guid = 'a7bdf640-f5cb-4acf-9de0-365b322d245c'
}, 'CimCmdlets', 'Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Utility', 'Microsoft.PowerShell.Security')
@@ -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
View File
@@ -42,6 +42,7 @@
$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
+58 -30
View File
@@ -12,6 +12,10 @@
[string[]] $Type,
[System.Collections.IDictionary] $LinksSummaryCache
)
$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]) {
@@ -73,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') {
@@ -81,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
@@ -100,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
@@ -112,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
@@ -277,8 +304,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" }
@@ -288,6 +315,7 @@
'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
+14 -11
View File
@@ -39,9 +39,11 @@ $GPOZaurrBrokenLink = [ordered] @{
}
Summary = {
New-HTMLText -FontSize 10pt -TextBlock {
"When GPO is deleted in a proper way it usually is removed from AD, SYSVOL and any link to it is also discarded. "
"Unfortunetly this is true only if the GPO is created and linked within same domain. "
"If GPO is linked in another domain, this leaves a broken link hanging on wherever it was linked before. "
"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 ',
@@ -49,14 +51,15 @@ $GPOZaurrBrokenLink = [ordered] @{
' broken links that need to be deleted over '
$Script:Reporting['GPOBrokenLink']['Variables']['UniqueObjects'].Count,
' unique objects. '
) -FontSize 10pt -FontWeight normal, bold, normal, bold, normal
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
) -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 {
+14 -9
View File
@@ -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 {
+36 -22
View File
@@ -49,11 +49,11 @@
}
if ($GPO.Days -le $Script:Reporting['GPOList']['Variables']['GPOOlderThan']) {
# Skip GPOS that are younger than 7 days
# Skip GPOS that are younger than 30 days
$Script:Reporting['GPOList']['Variables']['GPOSkip']++
}
if (($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 7 days
# Skip GPOS that are younger than 30 days
$Script:Reporting['GPOList']['Variables']['GPONotValidButSkip']++
}
if (($GPO.Enabled -eq $false -or $GPO.Empty -eq $true -or $GPO.Linked -eq $false -or $GPO.ApplyPermission -eq $false) -and $GPO.Days) {
@@ -149,7 +149,7 @@
}
}
Variables = @{
GPOOlderThan = 7
GPOOlderThan = 30
GPONotValidPerDomain = $null
GPOValidPerDomain = $null
GPONotOptimizedPerDomain = $null
@@ -214,9 +214,9 @@
}
} -Color Black, Red, Black, Red, Black
New-HTMLListItem -Text @(
"Group Policies ", "NOT", " valid, to skip: ", $Script:Reporting['GPOList']['Variables']['GPONotValidButSkip'], " (not older than $($Script:Reporting['GPOList']['Variables']['GPOOlderThan']) days)"
"Group Policies ", "NOT", " valid, to skip: ", $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 younger than $($Script:Reporting['GPOList']['Variables']['GPOOlderThan']) days: ", $Script:Reporting['GPOList']['Variables']['GPOSkip'], " (not older than $($Script:Reporting['GPOList']['Variables']['GPOOlderThan']) days)" -FontWeight normal, bold
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
@@ -292,6 +292,13 @@
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.'
}
Solution = {
New-HTMLSection -Invisible {
@@ -408,7 +415,7 @@
"You would do so using following approach "
) -FontSize 10pt -FontWeight bold, normal
New-HTMLCodeBlock -Code {
Remove-GPOZaurr -RequireDays 7 -Type Empty, Unlinked, Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor' {
Remove-GPOZaurr -RequireDays 30 -Type Empty, Unlinked, Disabled -BackupPath "$Env:UserProfile\Desktop\GPO" -LimitProcessing 2 -Verbose -IncludeDomains 'YourDomainYouHavePermissionsFor' {
Skip-GroupPolicy -Name 'TEST | Drive Mapping'
Skip-GroupPolicy -Name 'Default Domain Policy'
Skip-GroupPolicy -Name 'Default Domain Controllers Policy' -DomaiName 'JustOneDomain'
@@ -421,6 +428,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 ",
@@ -432,26 +446,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 -RequireDays 7 -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 -RequireDays 7 -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 -RequireDays 7 -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 -RequireDays 7 -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."
@@ -471,26 +485,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 -RequireDays 7 -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 -RequireDays 7 -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 -RequireDays 7 -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 -RequireDays 7 -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."
@@ -513,26 +527,26 @@
""
}
New-HTMLCodeBlock -Code {
Remove-GPOZaurr -RequireDays 7 -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 -RequireDays 7 -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 -RequireDays 7 -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 -RequireDays 7 -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. "
@@ -555,26 +569,26 @@
""
}
New-HTMLCodeBlock -Code {
Remove-GPOZaurr -RequireDays 7 -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 -RequireDays 7 -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 -RequireDays 7 -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 -RequireDays 7 -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. "
@@ -272,6 +272,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' {
+2 -2
View File
@@ -146,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."
@@ -299,7 +299,7 @@
"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
}
+13 -12
View File
@@ -77,18 +77,19 @@
#>
}
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
-29
View File
@@ -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
}
}
}
}
}
@@ -279,7 +279,14 @@
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 {
+2 -7
View File
@@ -3,14 +3,9 @@
param(
[System.Collections.IDictionary] $Support,
[string] $Path,
[switch] $Offline,
[switch] $Online,
[switch] $Open
)
$PSDefaultParameterValues = @{
"New-HTMLTable:WarningAction" = 'SilentlyContinue'
}
@@ -194,5 +189,5 @@
}
}
}
} -Online:(-not $Offline.IsPresent) -Open:$Open.IsPresent -FilePath $Path
} -Online:$Online.IsPresent -Open:$Open.IsPresent -FilePath $Path
}
+30
View File
@@ -336,6 +336,21 @@
}
}
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'
@@ -1252,6 +1267,21 @@
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Remote Management (WinRM)*' -SingleObject
}
}
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 = @(
@{
+5 -3
View File
@@ -100,9 +100,11 @@
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
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"
}
+44 -2
View File
@@ -1,4 +1,32 @@
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,
@@ -6,14 +34,22 @@ function Get-GPOZaurrBrokenLink {
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
[System.Collections.IDictionary] $ExtendedForestInformation
)
$ErrorFound = $false
$PoliciesAD = @{}
$ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExcludeDomainControllers $ExcludeDomainControllers -IncludeDomainControllers $IncludeDomainControllers -SkipRODC:$SkipRODC -ExtendedForestInformation $ExtendedForestInformation -Extended
# 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)
$PoliciesInAD = Get-ADObject -SearchBase $PoliciesSearchBase -SearchScope OneLevel -Filter * -Server $QueryServer -Properties Name, gPCFileSysPath, DisplayName, DistinguishedName, Description, Created, Modified, ObjectClass, ObjectGUID
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)"
@@ -34,6 +70,12 @@ function Get-GPOZaurrBrokenLink {
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]) {
+7 -7
View File
@@ -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") {
+7 -3
View File
@@ -12,7 +12,8 @@
[switch] $ShowWarning,
[alias('ForestName')][string] $Forest,
[string[]] $ExcludeDomains,
[alias('Domain', 'Domains')][string[]] $IncludeDomains
[alias('Domain', 'Domains')][string[]] $IncludeDomains,
[switch] $Online
)
Reset-GPOZaurrStatus # This makes sure types are at it's proper status
@@ -143,7 +144,10 @@
# Generate pretty HTML
$TimeLogHTML = Start-TimeLog
Write-Color -Text '[i]', '[HTML ] ', 'Generating HTML report' -Color Yellow, DarkGray, Yellow
if (-not $FilePath) {
$FilePath = Get-FileName -Extension 'html' -Temporary
}
Write-Color -Text '[i]', '[HTML ] ', "Generating HTML report ($FilePath)" -Color Yellow, DarkGray, Yellow
New-HTML -Author 'Przemysław Kłys' -TitleText 'GPOZaurr Report' {
New-HTMLTabStyle -BorderRadius 0px -TextTransform capitalize -BackgroundColorActive SlateGrey
New-HTMLSectionStyle -BorderRadius 0px -HeaderBackGroundColor Grey -RemoveShadow
@@ -182,7 +186,7 @@
}
}
}
} -Online -ShowHTML:(-not $HideHTML) -FilePath $FilePath
} -Online:$Online.IsPresent -ShowHTML:(-not $HideHTML) -FilePath $FilePath
$TimeLogEndHTML = Stop-TimeLog -Time $TimeLogHTML -Option OneLiner
Write-Color -Text '[i]', '[HTML ] ', 'Generating HTML report', " [Time to execute: $TimeLogEndHTML]" -Color Yellow, DarkGray, Yellow, DarkGray
if ($PassThru) {
+3
View File
@@ -95,7 +95,10 @@
$Output['CategoriesFull'] = [ordered] @{}
Write-Verbose "Invoke-GPOZaurrContent - Loading GPO Report to Categories"
$CountGPO = 0
[Array] $GPOCategories = foreach ($GPO in $GPOs) {
$CountGPO++
Write-Verbose "Invoke-GPOZaurrContent - Processing [$CountGPO/$($GPOs.Count)] $($GPO.DisplayName)"
if ($GPOPath) {
$GPOOutput = $GPO.GPOOutput
} else {
+2 -3
View File
@@ -7,8 +7,7 @@
[string] $Path,
[string] $Splitter = [System.Environment]::NewLine,
[switch] $PreventShow,
[switch] $Offline #,
# [switch] $ForceGPResult
[switch] $Online
)
# if user didn't choose anything, lets run as currently logged in user locally
if (-not $UserName -and -not $ComputerName) {
@@ -154,7 +153,7 @@
if ($Type -contains 'Object') {
$Output
} elseif ($Type -contains 'HTML') {
New-GPOZaurrReportHTML -Path $Path -Offline:$Offline -Open:(-not $PreventShow) -Support $Output
New-GPOZaurrReportHTML -Path $Path -Online:$Online -Open:(-not $PreventShow) -Support $Output
}
}
}
+5 -3
View File
@@ -108,21 +108,23 @@
}
if ($GPO.Status -in 'Not available on SYSVOL', 'ObjectClass issue') {
Write-Verbose "Remove-GPOZaurrBroken - Removing from AD [$($GPO.Status)] $($GPO.DistinguishedName)"
<#
try {
$ExistingObject = Get-ADObject -Identity $GPO.DistinguishedName -Server $GPO.DomainName -ErrorAction Stop
} catch {
Write-Warning "Remove-GPOZaurrBroken - Error getting $($GPO.DistinguishedName) from AD error: $($_.Exception.Message)"
$ExistingObject = $null
}
if ($ExistingObject -and $ExistingObject.ObjectClass -eq 'groupPolicyContainer') {
Write-Verbose "Remove-GPOZaurrBroken - Removing DN: $($GPO.DistinguishedName) / ObjectClass: $($ExistingObject.ObjectClass)"
#>
if ($GPO -and $GPO.ObjectClass -in 'groupPolicyContainer', 'Container') {
Write-Verbose "Remove-GPOZaurrBroken - Removing DN: $($GPO.DistinguishedName) / ObjectClass: $($GPO.ObjectClass)"
try {
Remove-ADObject -Server $GPO.DomainName -Identity $GPO.DistinguishedName -Recursive -Confirm:$false -ErrorAction Stop
} catch {
Write-Warning "Remove-GPOZaurrBroken - Failed to remove $($GPO.DistinguishedName) from AD error: $($_.Exception.Message)"
}
} else {
Write-Warning "Remove-GPOZaurrBroken - DistinguishedName $($GPO.DistinguishedName) not found or ObjectClass is not groupPolicyContainer ($($ExistingObject.ObjectClass))"
Write-Warning "Remove-GPOZaurrBroken - DistinguishedName $($GPO.DistinguishedName) not found or ObjectClass is not groupPolicyContainer/Container ($($GPO.ObjectClass))"
}
}
}
+46 -7
View File
@@ -1,4 +1,35 @@
function Repair-GPOZaurrBrokenLink {
<#
.SYNOPSIS
Removes any link to GPO that no longer exists.
.DESCRIPTION
Removes any link to GPO that no longer exists. It scans all site, organizational unit or domain root making sure every single link that may be linking to GPO that doesn't exists anymore is gone.
.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
.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
.EXAMPLE
Repair-GPOZaurrBrokenLink -Verbose -LimitProcessing 1 -WhatIf
.EXAMPLE
Repair-GPOZaurrBrokenLink -Verbose -IncludeDomains ad.evotec.pl -LimitProcessing 1 -WhatIf
.NOTES
General notes
#>
[cmdletBinding(SupportsShouldProcess)]
param(
[alias('ForestName')][string] $Forest,
@@ -7,7 +38,7 @@ function Repair-GPOZaurrBrokenLink {
[System.Collections.IDictionary] $ExtendedForestInformation,
[int] $LimitProcessing
)
$ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation -Extended
$ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -Extended
$Links = Get-GPOZaurrBrokenLink -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ForestInformation
$Cache = @{}
foreach ($Link in $Links) {
@@ -38,14 +69,22 @@ function Repair-GPOZaurrBrokenLink {
Write-Verbose "Repair-GPOZaurrBrokenLink - preparing for removal link to $GPODN ($Key)"
}
}
#
if ($Found) {
$NewGpLink = $($FixedLinks -join '')
try {
Write-Verbose "Repair-GPOZaurrBrokenLink - setting gpLink to $Key - $NewGPLink"
Set-ADObject -Identity $Key -Server $Server -Replace @{ gPLink = $NewGpLink } -ErrorAction Stop
} catch {
Write-Warning "Repair-GPOZaurrBrokenLink - couldn't replace gpLink at $Key with $NewGpLink"
if ($NewGpLink) {
try {
Write-Verbose "Repair-GPOZaurrBrokenLink - setting gpLink to $Key - $NewGPLink"
Set-ADObject -Identity $Key -Server $Server -Replace @{ gPLink = $NewGpLink } -ErrorAction Stop
} catch {
Write-Warning "Repair-GPOZaurrBrokenLink - setting gpLink to $Key - $NewGpLink failed! Error $($_.Exception.Message)"
}
} else {
try {
Write-Verbose "Repair-GPOZaurrBrokenLink - clearing gpLink for $Key (no other links)"
Set-ADObject -Identity $Key -Server $Server -Clear gPLink -ErrorAction Stop
} catch {
Write-Warning "Repair-GPOZaurrBrokenLink - clearing gpLink for $Key failed! Error $($_.Exception.Message)"
}
}
if ($LimitProcessing -eq $Count) {
break
+31
View File
@@ -1,4 +1,35 @@
function Repair-GPOZaurrNetLogonOwner {
<#
.SYNOPSIS
Sets new owner to each file in NetLogon share.
.DESCRIPTION
Sets new owner to each file in NetLogon share.
.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
.PARAMETER Principal
Provide named owner. If not provided default S-1-5-32-544 is used.
.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
.EXAMPLE
Repair-GPOZaurrNetLogonOwner -WhatIf -Verbose -IncludeDomains ad.evotec.pl
.NOTES
General notes
#>
[cmdletBinding(SupportsShouldProcess)]
param(
[alias('ForestName')][string] $Forest,
+3 -3
View File
@@ -35,7 +35,7 @@ $Configuration = @{
RequiredModules = @(
@{ ModuleName = 'PSSharedGoods'; ModuleVersion = 'Latest'; Guid = 'ee272aa8-baaa-4edf-9f45-b6d6f7d844fe' }
@{ ModuleName = 'ADEssentials'; ModuleVersion = 'Latest'; Guid = '9fc9fd61-7f11-4f4b-a527-084086f1905f' }
@{ ModuleName = 'PSWriteHTML'; ModuleVersion = "0.0.122"; Guid = 'a7bdf640-f5cb-4acf-9de0-365b322d245c' }
@{ ModuleName = 'PSWriteHTML'; ModuleVersion = "Latest"; Guid = 'a7bdf640-f5cb-4acf-9de0-365b322d245c' }
)
ExternalModuleDependencies = @(
#"ActiveDirectory"
@@ -277,10 +277,10 @@ $Configuration = @{
Verbose = $false
}
PublishModule = @{ # requires Enable to be on to process all of that
Enabled = $false
Enabled = $true
Prerelease = ''
RequireForce = $false
GitHub = $false
GitHub = $true
}
}
}
+68
View File
@@ -25,6 +25,7 @@
- [Table of Contents](#table-of-contents)
- [Installing](#installing)
- [Updating](#updating)
- [Resources](#resources)
- [Changelog](#changelog)
## Installing
@@ -55,8 +56,75 @@ That's it. Whenever there's a new version, you run the command, and you can enjo
**The essential thing** is if something works for you on production, keep using it till you test the new version on a test computer. I do changes that may not be big, but big enough that auto-update may break your code. For example, small rename to a parameter and your code stops working! Be responsible!
## Resources
To understand the usage I've created blog post you may find useful
- [The only command you will ever need to understand and fix your Group Policies (GPO)](https://evotec.xyz/the-only-command-you-will-ever-need-to-understand-and-fix-your-group-policies-gpo/)
## Changelog
- 0.0.121 - 2021.02.10
- [x] Improvement to `Get-GPOZaurr` - added description [#13](https://github.com/EvotecIT/GPOZaurr/issues/13)
- [x] Improvement to `Invoke-GPOZaurr -Type GPOList` - added description [#13](https://github.com/EvotecIT/GPOZaurr/issues/13)
- [x] Improved `Invoke-GPOZaurr`
- [x] Report GPOAnalysis - added `FolderRedirection`
- [x] Report GPOAnalysis - renamed `FolderRedirection` to `FolderRedirectionPolicy`
- [x] Improved `Invoke-GPOZaurrContent` as mentioned above for `GPOAnalysis`
- 0.0.120 - 2021.02.10
- [x] Improvement to `Get-GPOZaurr` to warn if there is potential issue with EMPTY (which can happen on non-english system)
- [x] In such case GPOZaurr will asses EMPTY or not using old method which doesn't detect all EMPTY cases but shouldn't provide false positives
- 0.0.119
- Broken release - weird
- 0.0.118 - 2021.02.09
- [x] Added information where the report is saved
- [x] Small improvement to `Get-GPOZaurr` to exlicitly define variable types
- 0.0.117 - 2021.02.09
- [x] Small fix to `Get-GPOZaurr` to exclude GPOList.xml which is used in offline mode by `Save-GPOZaurrFiles`
- 0.0.116 - 2021.02.08
- [x] Improved `Remove-GPOZaurrBroken` to handle ObjectClass problem, and removed reduntant check
- 0.0.115 - 2021.02.07
- [x] Improved `Invoke-GPOZaurr`
- [x] `GPOList` - clarified some texts, changed 7 days to 30 days as default
- [x] `NetLogonPermissions` - fixed missing text
- [x] Fixes `Get-GPOZaurrNetLogon` error on empty Owner - [#9](https://github.com/EvotecIT/GPOZaurr/issues/9)
- 0.0.114 - 2021.01.27
- [x] Improved `Invoke-GPOZaurr`
- [x] HTML now uses offline mode by default (no CDN) - increase in size of HTML up to 3MB
- [x] Using Online switch forces use of CDN - smaller files. For example `Invoke-GPOZaurr -Type GPOList -Online`
- [ ] Improved `Invoke-GPOZaurrSupport`
- [x] HTML now uses offline mode by default (no CDN) - increase in size of HTML up to 3MB
- [x] Using Online switch forces use of CDN - smaller files. For example `Invoke-GPOZaurrSupport -Online`
- [x] Removed parameter Offline, added parameter Online
- [x] The cmdlet is not really production ready. It's work in progress
- 0.0.113 - 2021.01.25
- [x] Improved `Invoke-GPOZaurr`
- [x] Report GPOAnalysis - added WindowsTimeService
- [x] Improved `Invoke-GPOZaurrContent`
- [x] Added `WindowsTimeService` type
- 0.0.112 - 2021.01.25
- [x] Improved `Invoke-GPOZaurr`
- 0.0.111 - 2021.01.24
- [x] Improved `Invoke-GPOZaurr`
- 0.0.110 - 2021.01.22
- [x] Improved `Invoke-GPOZaurr`
- 0.0.109 - 2021.01.11
- [x] Improved `Invoke-GPOZaurr`
- 0.0.108 - 2021.01.11
- [x] Improved `Invoke-GPOZaurr`
- [x] Improved `GPOConsistency`
- 0.0.107 - 2021.01.11
- [x] Improved `Invoke-GPOZaurr`
- 0.0.106 - 2021.01.11
- [x] Improved `Invoke-GPOZaurrContent`
- 0.0.105 - 2021.01.05
- [x] Improved `Get-GPOZaurr`
- [x] Improved report `GPOBrokenLink`
- 0.0.104 - 2021.01.04
- [x] Improved `Get-GPOZaurrBrokenLink`
- [x] Improved `Repair-GPOZaurrBrokenLink`
- [x] Improved `Get-GPOZaurr`
- [x] Improved report `GPOBrokenLink`
- 0.0.103 - 2021.01.04
- [x] Improved `Get-GPOZaurr`
- [x] Added new report `GPOBrokenLink`