From f841f41de0662b793150b2d0d3638f715377918d Mon Sep 17 00:00:00 2001 From: Przemyslaw Klys Date: Tue, 14 Jul 2020 23:54:22 +0200 Subject: [PATCH] Updates --- Examples/Example-29-FindGPO0.ps1 | 49 ++++---- Examples/Example-30-FindPolicyDefinitions.ps1 | 6 + GPOZaurr.psd1 | 2 +- Private/ConvertTo-AccountPolicies.ps1 | 40 ++++++ Private/ConvertTo-Audit.ps1 | 43 +++++++ Private/ConvertTo-EventLog.ps1 | 52 ++++++++ Private/ConvertTo-RegistryAutologon.ps1 | 50 ++++++++ Private/ConvertTo-Scripts.ps1 | 54 ++++++++ Private/ConvertTo-SoftwareInstallation.ps1 | 88 +++++++++++++ Private/Get-GPOCategories.ps1 | 62 +++++++++ Private/Invoke-GPOTranslation.ps1 | 20 ++- Private/Script.GPODictionary.ps1 | 118 +++++++++++------- Public/Get-GPOZaurrFiles.ps1 | 66 +++++++++- Public/Get-GPOZaurrFilesPolicyDefinition.ps1 | 96 ++++++++++++++ Public/Invoke-GPOZaurr.ps1 | 58 ++++++++- README.md | 3 +- 16 files changed, 726 insertions(+), 81 deletions(-) create mode 100644 Examples/Example-30-FindPolicyDefinitions.ps1 create mode 100644 Private/Get-GPOCategories.ps1 create mode 100644 Public/Get-GPOZaurrFilesPolicyDefinition.ps1 diff --git a/Examples/Example-29-FindGPO0.ps1 b/Examples/Example-29-FindGPO0.ps1 index 5e90896..6ce71d9 100644 --- a/Examples/Example-29-FindGPO0.ps1 +++ b/Examples/Example-29-FindGPO0.ps1 @@ -1,36 +1,29 @@ Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force #Invoke-GPOZaurr -OutputType Excel, Object, HTML -Open | Format-Table -$Output = Invoke-GPOZaurr -GPOPath $Env:USERPROFILE\Desktop\GPOExport -NoTranslation #| Format-Table +#$Output = Invoke-GPOZaurr -GPOPath $Env:USERPROFILE\Desktop\GPOExport -NoTranslation #| Format-Table +$Output = Invoke-GPOZaurr -GPOPath 'C:\Support\GitHub\GpoZaurr\Ignore\GPOExportTest' -NoTranslation +#$Output = Invoke-GPOZaurr -GPOPath 'C:\Support\GitHub\GpoZaurr\Ignore\GPOExport' -NoTranslation #-OutputType HTML, Object -Open #| Format-Table +#$Output.Categories | Out-HtmlView +#$Output.Categories | Format-Table +$Output | Format-Table +#$Output.CategoriesFull | Format-Table #$Output.Count +$Output.Reports | Format-Table +#$Output.Reports.Scripts | Format-Table * +#$Output.Reports.AccountPolicies | Format-Table * +#$Output.Reports.Audit | Format-Table * +#$Output.Reports.Autologon | Format-Table * +#$Output.Reports.EventLog | Format-Table * +$Output.Reports.SoftwareInstallation | Format-Table * -<# 4073 files - 212MB / no translation +return +# This is section that treats 1 GPO as single object - if there are 5 scripts in 1 GPO there's only one value -Days : 0 -Hours : 0 -Minutes : 0 -Seconds : 51 -Milliseconds : 756 -Ticks : 517566534 -TotalDays : 0,000599035340277778 -TotalHours : 0,0143768481666667 -TotalMinutes : 0,86261089 -TotalSeconds : 51,7566534 -TotalMilliseconds : 51756,6534 -#> - -<# 4073 files - 212MB / no translation / But with 2 diff types ($OutputByCategory / $OutputByGPO) -Days : 0 -Hours : 0 -Minutes : 0 -Seconds : 53 -Milliseconds : 246 -Ticks : 532466109 -TotalDays : 0,00061628021875 -TotalHours : 0,01479072525 -TotalMinutes : 0,887443515 -TotalSeconds : 53,2466109 -TotalMilliseconds : 53246,6109 -#> \ No newline at end of file +$Output = Invoke-GPOZaurr -GPOPath 'C:\Support\GitHub\GpoZaurr\Ignore\GPOExportTest' -NoTranslation -SingleObject +$Output +$Output.Reports | Format-Table +$Output.Reports.Scripts | Format-Table * +$Output.Reports.SoftwareInstallation | Format-Table * \ No newline at end of file diff --git a/Examples/Example-30-FindPolicyDefinitions.ps1 b/Examples/Example-30-FindPolicyDefinitions.ps1 new file mode 100644 index 0000000..c5cb68f --- /dev/null +++ b/Examples/Example-30-FindPolicyDefinitions.ps1 @@ -0,0 +1,6 @@ +Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force + +$Policies = Get-GPOZaurrFilesPolicyDefinitions -Signature +$Policies | Format-Table +#$Policies.FilesToDelete | Format-Table * +$Policies['ad.evotec.xyz'] | Format-Table * \ No newline at end of file diff --git a/GPOZaurr.psd1 b/GPOZaurr.psd1 index c8ce5d7..e2c2fb5 100644 --- a/GPOZaurr.psd1 +++ b/GPOZaurr.psd1 @@ -5,7 +5,7 @@ CompatiblePSEditions = 'Desktop' Copyright = '(c) 2011 - 2020 Przemyslaw Klys @ Evotec. All rights reserved.' Description = 'Group Policy Eater is a PowerShell module that aims to gather information about Group Policies but also allows easy fixing for issues that you may expect finding in them.' - FunctionsToExport = 'Add-GPOPermission', 'Add-GPOZaurrPermission', 'Backup-GPOZaurr', 'Get-GPOZaurr', 'Get-GPOZaurrAD', 'Get-GPOZaurrBackupInformation', 'Get-GPOZaurrFiles', 'Get-GPOZaurrLegacyFiles', 'Get-GPOZaurrLink', 'Get-GPOZaurrLinkSummary', 'Get-GPOZaurrOwner', 'Get-GPOZaurrPassword', 'Get-GPOZaurrPermission', 'Get-GPOZaurrPermissionConsistency', 'Get-GPOZaurrSysvol', 'Get-WMIFilter', 'Get-GPOZaurrWMI', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrPermission', 'New-GPOZaurrWMI', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrOrphanedSysvolFolders', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Select-GPOTranslation', 'Set-GPOOwner', 'Set-GPOZaurrOwner' + FunctionsToExport = 'Add-GPOPermission', 'Add-GPOZaurrPermission', 'Backup-GPOZaurr', 'Get-GPOZaurr', 'Get-GPOZaurrAD', 'Get-GPOZaurrBackupInformation', 'Get-GPOZaurrFiles', 'Get-GPOZaurrFilesPolicyDefinitions', 'Get-GPOZaurrLegacyFiles', 'Get-GPOZaurrLink', 'Get-GPOZaurrLinkSummary', 'Get-GPOZaurrOwner', 'Get-GPOZaurrPassword', 'Get-GPOZaurrPermission', 'Get-GPOZaurrPermissionConsistency', 'Get-GPOZaurrSysvol', 'Get-WMIFilter', 'Get-GPOZaurrWMI', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrPermission', 'New-GPOZaurrWMI', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrOrphanedSysvolFolders', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Select-GPOTranslation', 'Set-GPOOwner', 'Set-GPOZaurrOwner' GUID = 'f7d4c9e4-0298-4f51-ad77-e8e3febebbde' ModuleVersion = '0.0.48' PowerShellVersion = '5.1' diff --git a/Private/ConvertTo-AccountPolicies.ps1 b/Private/ConvertTo-AccountPolicies.ps1 index b3dcca1..651ab5e 100644 --- a/Private/ConvertTo-AccountPolicies.ps1 +++ b/Private/ConvertTo-AccountPolicies.ps1 @@ -28,4 +28,44 @@ function ConvertTo-AccountPolicies { $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } +} + +function ConvertTo-XMLAccountPolicies { + [cmdletBinding()] + param( + [PSCustomObject] $GPO + ) + $CreateGPO = [ordered]@{ + DisplayName = $GPO.DisplayName + DomainName = $GPO.DomainName + GUID = $GPO.GUID + GpoType = $GPO.GpoType + #GpoCategory = $GPOEntry.GpoCategory + #GpoSettings = $GPOEntry.GpoSettings + ClearTextPassword = 'Not Set' + LockoutBadCount = 'Not Set' + LockoutDuration = 'Not Set' + MaximumPasswordAge = 'Not Set' + MinimumPasswordAge = 'Not Set' + MinimumPasswordLength = 'Not Set' + PasswordComplexity = 'Not Set' + PasswordHistorySize = 'Not Set' + ResetLockoutCount = 'Not Set' + MaxClockSkew = 'Not Set' + MaxRenewAge = 'Not Set' + MaxServiceAge = 'Not Set' + MaxTicketAge = 'Not Set' + TicketValidateClient = 'Not Set' + } + foreach ($GPOEntry in $GPO.DataSet) { + if ($GPOEntry.SettingBoolean) { + $CreateGPO[$($GPOEntry.Name)] = if ($GPOEntry.SettingBoolean -eq 'true') { 'Enabled' } elseif ($GPOEntry.SettingBoolean -eq 'false') { 'Disabled' } else { 'Not set' }; + } elseif ($GPOEntry.SettingNumber) { + $CreateGPO[$($GPOEntry.Name)] = $GPOEntry.SettingNumber + } + } + $CreateGPO['Linked'] = $GPO.Linked + $CreateGPO['LinksCount'] = $GPO.LinksCount + $CreateGPO['Links'] = $GPO.Links + [PSCustomObject] $CreateGPO } \ No newline at end of file diff --git a/Private/ConvertTo-Audit.ps1 b/Private/ConvertTo-Audit.ps1 index e2b390a..0948504 100644 --- a/Private/ConvertTo-Audit.ps1 +++ b/Private/ConvertTo-Audit.ps1 @@ -32,4 +32,47 @@ $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } +} + +function ConvertTo-XMLAudit { + [cmdletBinding()] + param( + [PSCustomObject] $GPO, + [switch] $FullObject + ) + $CreateGPO = [ordered]@{ + DisplayName = $GPO.DisplayName + DomainName = $GPO.DomainName + GUID = $GPO.GUID + GpoType = $GPO.GpoType + #GpoCategory = $GPOEntry.GpoCategory + #GpoSettings = $GPOEntry.GpoSettings + AuditAccountLogon = 'No auditing' + AuditAccountManage = 'No auditing' + AuditDSAccess = 'No auditing' + AuditLogonEvents = 'No auditing' + AuditObjectAccess = 'No auditing' + AuditPolicyChange = 'No auditing' + AuditPrivilegeUse = 'No auditing' + AuditProcessTracking = 'No auditing' + AuditSystemEvents = 'No auditing' + } + foreach ($GPOEntry in $GPO.DataSet) { + $SuccessAttempts = try { [bool]::Parse($GPOEntry.SuccessAttempts) } catch { $null }; + $FailureAttempts = try { [bool]::Parse($GPOEntry.FailureAttempts) } catch { $null }; + if ($SuccessAttempts -and $FailureAttempts) { + $Setting = 'Success, Failure' + } elseif ($SuccessAttempts) { + $Setting = 'Success' + } elseif ($FailureAttempts) { + $Setting = 'Failure' + } else { + $Setting = 'No auditing' + } + $CreateGPO["$($GPOEntry.Name)"] = $Setting + } + $CreateGPO['Linked'] = $GPO.Linked + $CreateGPO['LinksCount'] = $GPO.LinksCount + $CreateGPO['Links'] = $GPO.Links + [PSCustomObject] $CreateGPO } \ No newline at end of file diff --git a/Private/ConvertTo-EventLog.ps1 b/Private/ConvertTo-EventLog.ps1 index 0c2b5bc..b03f96b 100644 --- a/Private/ConvertTo-EventLog.ps1 +++ b/Private/ConvertTo-EventLog.ps1 @@ -26,4 +26,56 @@ $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } +} + +function ConvertTo-XMLEventLog { + [cmdletBinding()] + param( + [PSCustomObject] $GPO + ) + $RetionPeriod = @{ + '0' = 'Overwrite events as needed' + '1' = 'Overwrite events by days' + '2' = 'Do not overwrite events (Clear logs manually)' + } + $CreateGPO = [ordered]@{ + DisplayName = $GPO.DisplayName + DomainName = $GPO.DomainName + GUID = $GPO.GUID + GpoType = $GPO.GpoType + #GpoCategory = $GPOEntry.GpoCategory + #GpoSettings = $GPOEntry.GpoSettings + ApplicationAuditLogRetentionPeriod = $null + ApplicationMaximumLogSize = $null + ApplicationRestrictGuestAccess = $null + ApplicationRetentionDays = $null + SystemAuditLogRetentionPeriod = $null + SystemMaximumLogSize = $null + SystemRestrictGuestAccess = $null + SystemRetentionDays = $null + SecurityAuditLogRetentionPeriod = $null + SecurityMaximumLogSize = $null + SecurityRestrictGuestAccess = $null + SecurityRetentionDays = $null + } + foreach ($GPOEntry in $GPO.DataSet) { + if ($GPOEntry.SettingBoolean) { + $CreateGPO["$($GPOEntry.Log)$($GPOEntry.Name)"] = if ($GPOEntry.SettingBoolean -eq 'true') { 'Enabled' } elseif ($GPOEntry.SettingBoolean -eq 'false') { 'Disabled' } else { 'Not set' }; + } elseif ($GPOEntry.SettingNumber) { + if ($GPOEntry.Name -eq 'AuditLogRetentionPeriod') { + if ($GPOEntry.SettingNumber) { + $CreateGPO["$($GPOEntry.Log)$($GPOEntry.Name)"] = $RetionPeriod[$($GPOEntry.SettingNumber)] + } else { + # Won't happen? + $CreateGPO["$($GPOEntry.Log)$($GPOEntry.Name)"] = $GPOEntry.SettingNumber + } + } else { + $CreateGPO["$($GPOEntry.Log)$($GPOEntry.Name)"] = $GPOEntry.SettingNumber + } + } + } + $CreateGPO['Linked'] = $GPO.Linked + $CreateGPO['LinksCount'] = $GPO.LinksCount + $CreateGPO['Links'] = $GPO.Links + [PSCustomObject] $CreateGPO } \ No newline at end of file diff --git a/Private/ConvertTo-RegistryAutologon.ps1 b/Private/ConvertTo-RegistryAutologon.ps1 index 80ff27f..b555e68 100644 --- a/Private/ConvertTo-RegistryAutologon.ps1 +++ b/Private/ConvertTo-RegistryAutologon.ps1 @@ -46,4 +46,54 @@ [PSCustomObject] $CreateGPO } } +} + +function ConvertTo-XMLRegistryAutologon { + [cmdletBinding()] + param( + [PSCustomObject] $GPO + ) + $CreateGPO = [ordered]@{ + DisplayName = $GPO.DisplayName + DomainName = $GPO.DomainName + GUID = $GPO.GUID + GpoType = $GPO.GpoType + #GpoCategory = $GPOEntry.GpoCategory + #GpoSettings = $GPOEntry.GpoSettings + AutoAdminLogon = $null + DefaultDomainName = $null + DefaultUserName = $null + DefaultPassword = $null + DateChangedAutoAdminLogon = $null + DateChangedDefaultDomainName = $null + DateChangedDefaultUserName = $null + DateChangedDefaultPassword = $null + } + foreach ($Registry in $GPO.DataSet.Registry) { + if ($Registry.Properties.Key -eq 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon') { + if ($Registry.Properties.Name -eq 'AutoAdminLogon') { + $CreateGPO['AutoAdminLogon'] = [bool] $Registry.Properties.value + $CreateGPO['DateChangedAutoAdminLogon'] = [DateTime] $Registry.changed + } elseif ($Registry.Properties.Name -eq 'DefaultDomainName') { + $CreateGPO['DefaultDomainName'] = $Registry.Properties.value + $CreateGPO['DateChangedDefaultDomainName'] = [DateTime] $Registry.changed + } elseif ($Registry.Properties.Name -eq 'DefaultUserName') { + $CreateGPO['DefaultUserName'] = $Registry.Properties.value + $CreateGPO['DateChangedDefaultUserName'] = [DateTime] $Registry.changed + } elseif ($Registry.Properties.Name -eq 'DefaultPassword') { + $CreateGPO['DefaultPassword'] = $Registry.Properties.value + $CreateGPO['DateChangedDefaultPassword'] = [DateTime] $Registry.changed + } + } + } + if ($null -ne $CreateGPO['AutoAdminLogon'] -or + $null -ne $CreateGPO['DefaultDomainName'] -or + $null -ne $CreateGPO['DefaultUserName'] -or + $null -ne $CreateGPO['DefaultPassword'] + ) { + $CreateGPO['Linked'] = $GPOEntry.Linked #: True + $CreateGPO['LinksCount'] = $GPOEntry.LinksCount #: 1 + $CreateGPO['Links'] = $GPOEntry.Links #: area1.local + [PSCustomObject] $CreateGPO + } } \ No newline at end of file diff --git a/Private/ConvertTo-Scripts.ps1 b/Private/ConvertTo-Scripts.ps1 index 05eb078..2eaa6da 100644 --- a/Private/ConvertTo-Scripts.ps1 +++ b/Private/ConvertTo-Scripts.ps1 @@ -23,4 +23,58 @@ [PSCustomObject] $CreateGPO } +} + +function ConvertTo-XMLScripts { + [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 + Data = $null + } + [Array] $CreateGPO['Data'] = foreach ($Script in $GPO.DataSet) { + [PSCustomObject] @{ + Type = $GPO.DataSet.Type + Command = $GPO.DataSet.Command + Parameters = $GPO.DataSet.Parameters + Order = $GPO.DataSet.Order + RunOrder = $GPO.DataSet.RunOrder + } + } + $CreateGPO['DataCount'] = $CreateGPO['Data'].Count + $CreateGPO['Linked'] = $GPO.Linked + $CreateGPO['LinksCount'] = $GPO.LinksCount + $CreateGPO['Links'] = $GPO.Links + [PSCustomObject] $CreateGPO + } else { + foreach ($Script in $GPO.DataSet) { + $CreateGPO = [ordered]@{ + DisplayName = $GPO.DisplayName + DomainName = $GPO.DomainName + GUID = $GPO.GUID + GpoType = $GPO.GpoType + #GpoCategory = $GPOEntry.GpoCategory + #GpoSettings = $GPOEntry.GpoSettings + Type = $Script.Type + Command = $Script.Command + Parameters = $Script.Parameters + Order = $Script.Order + RunOrder = $Script.RunOrder + } + $CreateGPO['Linked'] = $GPO.Linked + $CreateGPO['LinksCount'] = $GPO.LinksCount + $CreateGPO['Links'] = $GPO.Links + [PSCustomObject] $CreateGPO + } + } } \ No newline at end of file diff --git a/Private/ConvertTo-SoftwareInstallation.ps1 b/Private/ConvertTo-SoftwareInstallation.ps1 index 9380d77..283f6b2 100644 --- a/Private/ConvertTo-SoftwareInstallation.ps1 +++ b/Private/ConvertTo-SoftwareInstallation.ps1 @@ -39,4 +39,92 @@ $CreateGPO['Links'] = $GPOEntry.Links #: area1.local [PSCustomObject] $CreateGPO } +} + +function ConvertTo-XMLSoftwareInstallation { + [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 + Data = $null + } + [Array] $CreateGPO['Data'] = foreach ($MsiInstallerr in $GPO.DataSet) { + [PSCustomObject] @{ + Identifier = $MsiInstallerr.Identifier #: { 10495e9e-79c1-4a32-b278-a24cd495437f } + Name = $MsiInstallerr.Name #: Local Administrator Password Solution (2) + Path = $MsiInstallerr.Path #: \\area1.local\SYSVOL\area1.local\Policies\ { 5F5042A0-008F-45E3-8657-79C87BD002E3 }\LAPS.x64.msi + MajorVersion = $MsiInstallerr.MajorVersion #: 6 + MinorVersion = $MsiInstallerr.MinorVersion #: 2 + LanguageId = $MsiInstallerr.LanguageId #: 1033 + Architecture = $MsiInstallerr.Architecture #: 9 + IgnoreLanguage = if ($MsiInstallerr.IgnoreLanguage -eq 'true') { $true } else { $false } #: false + Allowx86Onia64 = if ($MsiInstallerr.Allowx86Onia64 -eq 'true') { $true } else { $false } #: true + SupportURL = $MsiInstallerr.SupportURL #: + AutoInstall = if ($MsiInstallerr.AutoInstall -eq 'true') { $true } else { $false } #: true + DisplayInARP = if ($MsiInstallerr.DisplayInARP -eq 'true') { $true } else { $false } #: true + IncludeCOM = if ($MsiInstallerr.IncludeCOM -eq 'true') { $true } else { $false } #: true + SecurityDescriptor = $MsiInstallerr.SecurityDescriptor #: SecurityDescriptor + DeploymentType = $MsiInstallerr.DeploymentType #: Assign + ProductId = $MsiInstallerr.ProductId #: { ea8cb806-c109 - 4700 - 96b4-f1f268e5036c } + ScriptPath = $MsiInstallerr.ScriptPath #: \\area1.local\SysVol\area1.local\Policies\ { 5F5042A0-008F-45E3-8657-79C87BD002E3 }\Machine\Applications\ { EAC9B821-FB4D - 457A-806F-E5B528D1E41A }.aas + DeploymentCount = $MsiInstallerr.DeploymentCount #: 0 + InstallationUILevel = $MsiInstallerr.InstallationUILevel #: Maximum + Upgrades = if ($MsiInstallerr.Upgrades.Mandatory -eq 'true') { $true } else { $false } #: Upgrades + UninstallUnmanaged = if ($MsiInstallerr.UninstallUnmanaged -eq 'true') { $true } else { $false } #: false + LossOfScopeAction = $MsiInstallerr.LossOfScopeAction #: Unmanage + } + } + $CreateGPO['Count'] = $CreateGPO['Data'].Count + $CreateGPO['Linked'] = $GPO.Linked + $CreateGPO['LinksCount'] = $GPO.LinksCount + $CreateGPO['Links'] = $GPO.Links + [PSCustomObject] $CreateGPO + } else { + foreach ($MsiInstallerr in $GPO.DataSet) { + $CreateGPO = [ordered]@{ + DisplayName = $GPO.DisplayName + DomainName = $GPO.DomainName + GUID = $GPO.GUID + GpoType = $GPO.GpoType + #GpoCategory = $GPOEntry.GpoCategory + #GpoSettings = $GPOEntry.GpoSettings + Identifier = $MsiInstallerr.Identifier #: { 10495e9e-79c1-4a32-b278-a24cd495437f } + Name = $MsiInstallerr.Name #: Local Administrator Password Solution (2) + Path = $MsiInstallerr.Path #: \\area1.local\SYSVOL\area1.local\Policies\ { 5F5042A0-008F-45E3-8657-79C87BD002E3 }\LAPS.x64.msi + MajorVersion = $MsiInstallerr.MajorVersion #: 6 + MinorVersion = $MsiInstallerr.MinorVersion #: 2 + LanguageId = $MsiInstallerr.LanguageId #: 1033 + Architecture = $MsiInstallerr.Architecture #: 9 + IgnoreLanguage = if ($MsiInstallerr.IgnoreLanguage -eq 'true') { $true } else { $false } #: false + Allowx86Onia64 = if ($MsiInstallerr.Allowx86Onia64 -eq 'true') { $true } else { $false } #: true + SupportURL = $MsiInstallerr.SupportURL #: + AutoInstall = if ($MsiInstallerr.AutoInstall -eq 'true') { $true } else { $false } #: true + DisplayInARP = if ($MsiInstallerr.DisplayInARP -eq 'true') { $true } else { $false } #: true + IncludeCOM = if ($MsiInstallerr.IncludeCOM -eq 'true') { $true } else { $false } #: true + SecurityDescriptor = $MsiInstallerr.SecurityDescriptor #: SecurityDescriptor + DeploymentType = $MsiInstallerr.DeploymentType #: Assign + ProductId = $MsiInstallerr.ProductId #: { ea8cb806-c109 - 4700 - 96b4-f1f268e5036c } + ScriptPath = $MsiInstallerr.ScriptPath #: \\area1.local\SysVol\area1.local\Policies\ { 5F5042A0-008F-45E3-8657-79C87BD002E3 }\Machine\Applications\ { EAC9B821-FB4D - 457A-806F-E5B528D1E41A }.aas + DeploymentCount = $MsiInstallerr.DeploymentCount #: 0 + InstallationUILevel = $MsiInstallerr.InstallationUILevel #: Maximum + Upgrades = if ($MsiInstallerr.Upgrades.Mandatory -eq 'true') { $true } else { $false } #: Upgrades + UninstallUnmanaged = if ($MsiInstallerr.UninstallUnmanaged -eq 'true') { $true } else { $false } #: false + LossOfScopeAction = $MsiInstallerr.LossOfScopeAction #: Unmanage + } + $CreateGPO['Linked'] = $GPO.Linked + $CreateGPO['LinksCount'] = $GPO.LinksCount + $CreateGPO['Links'] = $GPO.Links + [PSCustomObject] $CreateGPO + } + } } \ No newline at end of file diff --git a/Private/Get-GPOCategories.ps1 b/Private/Get-GPOCategories.ps1 new file mode 100644 index 0000000..1a13dbd --- /dev/null +++ b/Private/Get-GPOCategories.ps1 @@ -0,0 +1,62 @@ +function Get-GPOCategories { + [cmdletBinding()] + param( + [PSCustomObject] $GPO, + [System.Xml.XmlElement[]] $GPOOutput, + [string] $Splitter, + [switch] $FullObjects, + [System.Collections.IDictionary] $CachedCategories + ) + if (-not $CachedCategories) { + $CachedCategories = [ordered] @{} + } + $LinksInformation = Get-LinksFromXML -GPOOutput $GPOOutput -Splitter $Splitter -FullObjects:$FullObjects + foreach ($GpoType in @('User', 'Computer')) { + if ($GPOOutput.$GpoType.ExtensionData.Extension) { + foreach ($ExtensionType in $GPOOutput.$GpoType.ExtensionData.Extension) { + # It's possible that one of the ExtensionType records has value null. Weird but happend. + 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-XMLStandard - things went sideways $($_.Exception.Message)" + continue + } + + foreach ($GpoSettings in $KeysToLoop.Name) { + $Template = [ordered] @{ + DisplayName = $GPO.DisplayName + DomainName = $GPO.DomainName + GUID = $GPO.Guid + GpoType = $GpoType + GpoCategory = $GPOSettingTypeSplit[1] + GpoSettings = $GpoSettings + } + $Template['Linked'] = $LinksInformation.Linked + $Template['LinksCount'] = $LinksInformation.LinksCount + $Template['Links'] = $LinksInformation.Links + $Template['IncludeComments'] = [bool]::Parse($GPOOutput.IncludeComments) + $Template['CreatedTime'] = [DateTime] $GPOOutput.CreatedTime + $Template['ModifiedTime'] = [DateTime] $GPOOutput.ModifiedTime + $Template['ReadTime'] = [DateTime] $GPOOutput.ReadTime + $Template['SecurityDescriptor'] = $GPOOutput.SecurityDescriptor + $Template['FilterDataAvailable'] = [bool]::Parse($GPOOutput.FilterDataAvailable) + $Template['DataSet'] = $ExtensionType.$GpoSettings + $ConvertedObject = [PSCustomObject] $Template + + if (-not $CachedCategories["$($Template.GpoCategory)"]) { + $CachedCategories["$($Template.GpoCategory)"] = [ordered] @{} + } + if (-not $CachedCategories["$($Template.GpoCategory)"]["$($Template.GpoSettings)"]) { + $CachedCategories["$($Template.GpoCategory)"]["$($Template.GpoSettings)"] = [System.Collections.Generic.List[PSCustomObject]]::new() + } + $CachedCategories["$($Template.GpoCategory)"]["$($Template.GpoSettings)"].Add($ConvertedObject) + # return GPOCategory + $ConvertedObject + } + } + } + } + } +} \ No newline at end of file diff --git a/Private/Invoke-GPOTranslation.ps1 b/Private/Invoke-GPOTranslation.ps1 index af7aa63..879cfb5 100644 --- a/Private/Invoke-GPOTranslation.ps1 +++ b/Private/Invoke-GPOTranslation.ps1 @@ -1,4 +1,4 @@ -function Invoke-GPOTranslation { +function Invoke-GPOTranslationOld { [cmdletBinding()] param( [System.Collections.IDictionary] $InputData, @@ -12,4 +12,20 @@ return & $Script:GPODitionary[$Report]['Code'] } } -} \ No newline at end of file +} + +function Invoke-GPOTranslation { + [cmdletBinding()] + param( + [Array] $InputData, + [string] $Report, + [string] $Category, + [string] $Settings + ) + if ($Category -and $Settings -and $InputData) { + if ($Script:GPODitionary[$Report]['Code']) { + $Script:GPOList = $InputData + return & $Script:GPODitionary[$Report]['Code'] + } + } +} diff --git a/Private/Script.GPODictionary.ps1 b/Private/Script.GPODictionary.ps1 index e46c0a3..9bd0389 100644 --- a/Private/Script.GPODictionary.ps1 +++ b/Private/Script.GPODictionary.ps1 @@ -1,50 +1,66 @@ $Script:GPODitionary = [ordered] @{ - AccountPolicies = [ordered] @{ - Category = 'SecuritySettings' - Settings = 'Account' - GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Account Policies' - Code = { - ConvertTo-AccountPolicies -GPOList $GPOList + AccountPolicies = [ordered] @{ + Category = 'SecuritySettings' + Settings = 'Account' + GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Account Policies' + Code = { + #ConvertTo-AccountPolicies -GPOList $GPOList + ConvertTo-XMLAccountPolicies -GPO $GPO + } + CodeSingle = { + #ConvertTo-AccountPolicies -GPOList $GPOList + ConvertTo-XMLAccountPolicies -GPO $GPO } } - Audit = [ordered] @{ - Category = 'SecuritySettings' - Settings = 'Audit' + Audit = [ordered] @{ + Category = 'SecuritySettings' + Settings = 'Audit' #GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Account Policies' - Code = { - ConvertTo-Audit -GPOList $GPOList + Code = { + ConvertTo-XMLAudit -GPO $GPO + #ConvertTo-Audit -GPOList $GPOList + } + CodeSingle = { + ConvertTo-XMLAudit -GPO $GPO + #ConvertTo-Audit -GPOList $GPOList } } - AuditAlternative = [ordered] @{ - Category = 'SecuritySettings' - Settings = 'Audit' + Autologon = [ordered] @{ + Category = 'RegistrySettings' + Settings = 'RegistrySettings' + Code = { + #ConvertTo-RegistryAutologon -GPOList $GPOList + ConvertTo-XMLRegistryAutologon -GPO $GPO + } + CodeSingle = { + #ConvertTo-AccountPolicies -GPOList $GPOList + ConvertTo-XMLRegistryAutologon -GPO $GPO + } + } + EventLog = [ordered] @{ + Category = 'SecuritySettings' + Settings = 'EventLog' #GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Account Policies' - Code = { - ConvertTo-AuditAlternative -GPOList $GPOList + Code = { + #ConvertTo-EventLog -GPOList $GPOList + ConvertTo-XMLEventLog -GPO $GPO + } + CodeSingle = { + #ConvertTo-EventLog -GPOList $GPOList + ConvertTo-XMLEventLog -GPO $GPO } } - Autologon = [ordered] @{ - Category = 'RegistrySettings' - Settings = 'RegistrySettings' - Code = { - ConvertTo-RegistryAutologon -GPOList $GPOList - } - } - EventLog = [ordered] @{ - Category = 'SecuritySettings' - Settings = 'EventLog' - #GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Account Policies' - Code = { - ConvertTo-EventLog -GPOList $GPOList - } - } - LocalUsersAndGroups = [ordered] @{ + <# + LocalUsersAndGroups = [ordered] @{ Category = 'LugsSettings' Settings = 'LocalUsersAndGroups' Code = { - ConvertTo-LocalUserAndGroups -GPOList $GPOList + #ConvertTo-LocalUserAndGroups -GPOList $GPOList + ConvertTo-XMLLocalUserAndGroups -GPO $GPO } } + #> + <# Policies = @{ Category = 'RegistrySettings' Settings = 'Policy' @@ -66,13 +82,19 @@ ConvertTo-RegistrySettingsCollection -GPOList $GPOList } } - Scripts = [ordered] @{ - Category = 'Scripts' - Settings = 'Script' - Code = { - ConvertTo-Scripts -GPOList $GPOList + #> + Scripts = [ordered] @{ + Category = 'Scripts' + Settings = 'Script' + Code = { + #ConvertTo-Scripts -GPOList $GPOList + ConvertTo-XMLScripts -GPO $GPO + } + CodeSingle = { + ConvertTo-XMLScripts -GPO $GPO -SingleObject } } + <# SecurityOptions = [ordered] @{ Category = 'SecuritySettings' Settings = 'SecurityOptions' @@ -80,13 +102,19 @@ ConvertTo-SecurityOptions -GPOList $GPOList } } - SoftwareInstallation = [ordered] @{ - Category = 'SoftwareInstallationSettings' - Settings = 'MsiApplication' - Code = { - ConvertTo-SoftwareInstallation -GPOList $GPOList + #> + SoftwareInstallation = [ordered] @{ + Category = 'SoftwareInstallationSettings' + Settings = 'MsiApplication' + Code = { + # ConvertTo-SoftwareInstallation -GPOList $GPOList + ConvertTo-XMLSoftwareInstallation -GPO $GPO + } + CodeSingle = { + ConvertTo-XMLSoftwareInstallation -GPO $GPO -SingleObject } } + <# SystemServices = [ordered] @{ Description = '' GPOPath = 'Computer Configuration -> Policies -> Windows Settings -> Security Settings -> System Services' @@ -105,7 +133,5 @@ ConvertTo-SystemServicesNT -GPOList $GPOList } } - #LugsSettings = @{ - # LocalUsersAndGroups = $LugsSettingsLocalUsersAndGroups - + #> } \ No newline at end of file diff --git a/Public/Get-GPOZaurrFiles.ps1 b/Public/Get-GPOZaurrFiles.ps1 index be45e20..ef74b55 100644 --- a/Public/Get-GPOZaurrFiles.ps1 +++ b/Public/Get-GPOZaurrFiles.ps1 @@ -8,7 +8,12 @@ [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation ) + $GPOCache = @{} $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation + $GPOList = Get-GPOZaurrAD -ExtendedForestInformation $ForestInformation + foreach ($GPO in $GPOList) { + $GPOCache[$GPO.GUID] = $GPO + } foreach ($Domain in $ForestInformation.Domains) { $Path = @( if ($Type -contains 'All') { @@ -21,11 +26,68 @@ "\\$Domain\NETLOGON" } ) + $Folders = @{ + "\\$Domain\SYSVOL\$Domain\policies\PolicyDefinitions" = @{ + Name = 'SYSVOL PolicyDefinitions' + } + "\\$Domain\SYSVOL\$Domain\policies" = @{ + Name = 'SYSVOL Policies' + + } + "\\$Domain\SYSVOL\$Domain\scripts" = @{ + Name = 'NETLOGON Scripts' + } + "\\$Domain\SYSVOL\$Domain\StarterGPOs" = @{ + Name = 'SYSVOL GPO Starters' + } + "\\$Domain\NETLOGON" = @{ + Name = 'NETLOGON Scripts' + } + } + + + Get-ChildItem -Path $Path -ErrorAction SilentlyContinue -Recurse -ErrorVariable err -File | ForEach-Object { - Get-FileMetaData -File $_ -Signature -HashAlgorithm $HashAlgorithm + $BelongsToGPO = $false + $GPODisplayName = $null + $SuggestedAction = $null + $FileType = foreach ($Key in $Folders.Keys) { + if ($_.FullName -like "$Key*") { + $Folders[$Key] + break + } + } + if ($FileType.Name -eq 'SYSVOL Policies') { + $Test = $_.FullName -match '[\da-zA-Z]{8}-([\da-zA-Z]{4}-){3}[\da-zA-Z]{12}' + if ($Test) { + $GPO = $GPOCache[$matches[0]] + if ($GPO) { + $BelongsToGPO = $true + $GPODisplayName = $GPO.DisplayName + } + } + } + if ($_.Extension -eq '.adm') { + $SuggestedAction = 'Delete legacy ADM file' + } elseif ($_.Extension -in @('.admx', '.adml') -and $FileType.Name -eq 'SYSVOL PolicyDefinitions') { + $SuggestedAction = 'Skip assesment' + } + + + $MetaData = Get-FileMetaData -File $_ -Signature #-HashAlgorithm $HashAlgorithm + Add-Member -InputObject $MetaData -Name 'AssesmentType' -Value $FileType.Name -MemberType NoteProperty + Add-Member -InputObject $MetaData -Name 'BelongsToGPO' -Value $BelongsToGPO -MemberType NoteProperty + Add-Member -InputObject $MetaData -Name 'GPODisplayName' -Value $GPODisplayName -MemberType NoteProperty + Add-Member -InputObject $MetaData -Name 'SuggestedAction' -Value $SuggestedAction -MemberType NoteProperty + + + + $MetaData } foreach ($e in $err) { Write-Warning "Get-GPOZaurrFiles - $($e.Exception.Message) ($($e.CategoryInfo.Reason))" } } -} \ No newline at end of file +} + +#Get-GPOZaurrFiles | ConvertTo-Excel -OpenWorkBook -FilePath $Env:USERPROFILE\GPOTesting.xlsx -ExcelWorkSheetName 'GPO Output' -AutoFilter -AutoFit -FreezeTopRowFirstColumn \ No newline at end of file diff --git a/Public/Get-GPOZaurrFilesPolicyDefinition.ps1 b/Public/Get-GPOZaurrFilesPolicyDefinition.ps1 new file mode 100644 index 0000000..f53d25b --- /dev/null +++ b/Public/Get-GPOZaurrFilesPolicyDefinition.ps1 @@ -0,0 +1,96 @@ +function Get-GPOZaurrFilesPolicyDefinitions { + [cmdletbinding()] + param( + [alias('ForestName')][string] $Forest, + [string[]] $ExcludeDomains, + [alias('Domain', 'Domains')][string[]] $IncludeDomains, + [System.Collections.IDictionary] $ExtendedForestInformation, + + [switch] $Signature + ) + $Output = [ordered] @{ + FilesToDelete = [System.Collections.Generic.List[Object]]::new() + } + $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation + $FilesCache = @{} + foreach ($Domain in $ForestInformation.Domains) { + $Output[$Domain] = [ordered] @{} + $FilesCache[$Domain] = [ordered] @{} + $Directories = Get-ChildItem -Path "\\$Domain\SYSVOL\$Domain\policies\PolicyDefinitions" -Directory -ErrorAction SilentlyContinue -ErrorVariable err + [Array] $Languages = foreach ($Directory in $Directories) { + if ($Directory.BaseName.Length -eq 5) { + $Directory.BaseName + } + } + $Files = Get-ChildItem -Path "\\$Domain\SYSVOL\$Domain\policies\PolicyDefinitions" -ErrorAction SilentlyContinue -ErrorVariable +err -File #| Select-Object Name, FullName, CreationTime, LastWriteTime, Attributes + foreach ($File in $Files) { + $FilesCache[$Domain][$($File.BaseName)] = [ordered] @{ + Name = $File.BaseName + FullName = $File.FullName + IsReadOnly = $File.IsReadOnly + CreationTime = $File.CreationTime + LastAccessTime = $File.LastAccessTime + LastWriteTime = $File.LastWriteTime + IsConsistent = $false + } + foreach ($Language in $Languages) { + $FilesCache[$Domain][$($File.BaseName)][$Language] = $false + } + if ($Signature) { + $DigitalSignature = Get-AuthenticodeSignature -FilePath $File.FullName + $FilesCache[$Domain][$($File.BaseName)]['SignatureStatus'] = $DigitalSignature.Status + $FilesCache[$Domain][$($File.BaseName)]['SignatureCertificateSubject'] = $DigitalSignature.SignerCertificate.Subject + $FilesCache[$Domain][$($File.BaseName)]['SignatureCertificateIssuer'] = $DigitalSignature.SignerCertificate.Issuer + $FilesCache[$Domain][$($File.BaseName)]['SignatureCertificateSerialNumber'] = $DigitalSignature.SignerCertificate.SerialNumber + $FilesCache[$Domain][$($File.BaseName)]['SignatureCertificateNotBefore'] = $DigitalSignature.SignerCertificate.NotBefore + $FilesCache[$Domain][$($File.BaseName)]['SignatureCertificateNotAfter'] = $DigitalSignature.SignerCertificate.NotAfter + $FilesCache[$Domain][$($File.BaseName)]['SignatureCertificateThumbprint'] = $DigitalSignature.SignerCertificate.Thumbprint + $FilesCache[$Domain][$($File.BaseName)]['IsOSBinary'] = $DigitalSignature.IsOSBinary + } + } + foreach ($Directory in $Directories) { + $FilesLanguage = Get-ChildItem -Path $Directory.FullName -ErrorAction SilentlyContinue -ErrorVariable +err + foreach ($FileLanguage in $FilesLanguage) { + if ($FileLanguage.Extension -eq '.adml') { + if ($FilesCache[$Domain][$FileLanguage.BaseName]) { + $FilesCache[$Domain][$FileLanguage.BaseName][$Directory.Name] = $true + } else { + #Write-Warning "Get-GPOZaurrFilesPolicyDefinitions - File $($FileLanguage.FullName) doesn't have a match." + $Output.FilesToDelete.Add( + [PSCustomobject] @{ + Name = $FileLanguage.BaseName + FullName = $FileLanguage.FullName + IsReadOnly = $FileLanguage.IsReadOnly + CreationTime = $FileLanguage.CreationTime + LastAccessTime = $FileLanguage.LastAccessTime + LastWriteTime = $FileLanguage.LastWriteTime + } + ) + } + } else { + + } + } + } + + foreach ($e in $err) { + Write-Warning "Get-GPOZaurrLegacy - $($e.Exception.Message) ($($e.CategoryInfo.Reason))" + } + $ExcludeProperty = @( + 'Name', 'FullName', 'IsReadOnly', 'CreationTime', 'LastAccessTime', 'LastWriteTime', 'IsConsistent' + 'SignatureCertificateSubject', 'SignatureCertificateIssuer', 'SignatureCertificateSerialNumber', 'SignatureCertificateNotBefore' + 'SignatureCertificateNotAfter', 'SignatureCertificateThumbprint', 'SignatureStatus', 'IsOSBinary' + ) + $Properties = Select-Properties -Objects $FilesCache[$Domain][0] -ExcludeProperty $ExcludeProperty + $Output[$Domain] = foreach ($File in $FilesCache[$Domain].Keys) { + $Values = foreach ($Property in $Properties) { + $FilesCache[$Domain][$File][$Property] + } + if ($Values -notcontains $false) { + $FilesCache[$Domain][$File]['IsConsistent'] = $true + } + [PSCustomObject] $FilesCache[$Domain][$File] + } + } + $Output +} \ No newline at end of file diff --git a/Public/Invoke-GPOZaurr.ps1 b/Public/Invoke-GPOZaurr.ps1 index 3b965c2..a6f3001 100644 --- a/Public/Invoke-GPOZaurr.ps1 +++ b/Public/Invoke-GPOZaurr.ps1 @@ -34,7 +34,15 @@ [Parameter(ParameterSetName = 'Default')] [Parameter(ParameterSetName = 'Local')] - [switch] $Open + [switch] $Open, + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'Local')] + [switch] $CategoriesOnly, + + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'Local')] + [switch] $SingleObject ) if ($Type.Count -eq 0) { $Type = $Script:GPODitionary.Keys @@ -71,6 +79,54 @@ $Output = [ordered] @{} $OutputByGPO = [ordered] @{} $TranslatedOutput = [ordered] @{} + $CachedCategories = [ordered] @{} + + [Array] $GPOCategories = foreach ($GPO in $GPOs) { + if ($GPOPath) { + $GPOOutput = $GPO.GPOOutput + } else { + [xml] $GPOOutput = Get-GPOReport -Guid $GPO.GUID -Domain $GPO.DomainName -ReportType Xml + } + Get-GPOCategories -GPO $GPO -GPOOutput $GPOOutput.GPO -Splitter $Splitter -FullObjects:$FullObjects -CachedCategories $CachedCategories + } + + # Return Categories or save it + if ($CategoriesOnly) { + return $GPOCategories | Select-Object -Property * -ExcludeProperty DataSet + } else { + $Output['Categories'] = $GPOCategories | Select-Object -Property * -ExcludeProperty DataSet + } + # Save Cached Categories + $Output['CategoriesFull'] = $CachedCategories + # Process Reporting + $Output['Reports'] = [ordered] @{} + foreach ($Report in $Type) { + $Category = $Script:GPODitionary[$Report]['Category'] + $Settings = $Script:GPODitionary[$Report]['Settings'] + + $CategorizedGPO = $CachedCategories[$Category][$Settings] + foreach ($GPO in $CategorizedGPO) { + if (-not $Output['Reports'][$Report]) { + $Output['Reports'][$Report] = [System.Collections.Generic.List[PSCustomObject]]::new() + } + if ($SingleObject) { + if ($Script:GPODitionary[$Report]['CodeSingle']) { + $TranslatedGpo = Invoke-Command -ScriptBlock $Script:GPODitionary[$Report]['CodeSingle'] + $Output['Reports'][$Report].Add($TranslatedGpo) + } + } else { + if ($Script:GPODitionary[$Report]['Code']) { + $TranslatedGpo = Invoke-Command -ScriptBlock $Script:GPODitionary[$Report]['Code'] + $Output['Reports'][$Report].Add($TranslatedGpo) + } + } + } + } + + + + return $Output + foreach ($GPO in $GPOs) { if ($GPOPath) { $GPOOutput = $GPO.GPOOutput diff --git a/README.md b/README.md index f956f61..e7a12cb 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,8 @@ That's it. Whenever there's a new version, you run the command, and you can enjo ## Changelog - 0.0.48 - Unreleased - + - Added `Get-GPOZaurrFilesPolicyDefinitions` + - Updates to `Invoke-GPOZaurr` - still work in progress - 0.0.47 - 29.06.2020 - Update to `Get-GPOZaurrAD` for better error reporting - Updates to `Invoke-GPOZaurr` - still work in progress