mirror of
https://github.com/EvotecIT/GPOZaurr.git
synced 2026-07-26 20:00:09 +00:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0383d249e9 | |||
| 8070179d27 | |||
| db67e6191e | |||
| db9b6d60c6 | |||
| 2c965d81d5 | |||
| bff372affe | |||
| 138a0f411e | |||
| 1c37a9d1df | |||
| 30535c1baf | |||
| 56c722edd0 | |||
| 1f43ae21fe | |||
| ef90ef05f7 | |||
| 43b304d252 | |||
| 24e691edb9 | |||
| 1c787735d4 | |||
| 13a2aa6482 | |||
| 1ac1f83abd | |||
| 65b2867588 | |||
| 1043a2d512 | |||
| 7002813027 | |||
| 03b8e4f2cb | |||
| 680762733e | |||
| 7a37d5b9f6 | |||
| a1e9a4a3fa | |||
| 8cbb3272b2 | |||
| 8da0c1793d | |||
| 5a7b20ca2b | |||
| ebffba3b95 | |||
| a79071c395 | |||
| a5a889b468 | |||
| 62d73041ea | |||
| d88307047c | |||
| 7d85d41747 | |||
| a1fab2ceb2 | |||
| 99f07f61e3 | |||
| 58136f0c43 | |||
| b55729d8e0 | |||
| 6206a33a2e | |||
| 165381b1e3 | |||
| ea1de10fd9 | |||
| 03453b6bdb | |||
| 4d7f49902d | |||
| 508d778d06 | |||
| 5c3157f15f | |||
| b33f42b320 | |||
| f8d3b363e7 | |||
| a68d917d19 | |||
| 946bb3029f | |||
| 975bf5b889 | |||
| 6fa0818375 | |||
| 2abec9579a | |||
| 75a8083368 | |||
| 06c711694e | |||
| 8a38ac4556 | |||
| 9d2ae288c0 | |||
| 0bc50328ee | |||
| a74b662c9b | |||
| 37d8db92f7 | |||
| d094344f9f |
@@ -1,3 +1,3 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
Get-GPOZaurrLink | Format-Table -AutoSize *
|
||||
Get-GPOZaurrLink -Verbose | Format-Table -AutoSize *
|
||||
@@ -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
|
||||
@@ -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,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
|
||||
@@ -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
@@ -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.119'
|
||||
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')
|
||||
|
||||
@@ -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
|
||||
|
||||
+57
-30
@@ -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 ($ExtensionType.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" }
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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' {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -1252,6 +1252,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 = @(
|
||||
@{
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Installing](#installing)
|
||||
- [Updating](#updating)
|
||||
- [Resources](#resources)
|
||||
- [Changelog](#changelog)
|
||||
|
||||
## Installing
|
||||
@@ -55,8 +56,66 @@ 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.119 - 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.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`
|
||||
|
||||
Reference in New Issue
Block a user