mirror of
https://github.com/EvotecIT/GPOZaurr.git
synced 2026-07-26 20:00:09 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65f52058d3 | |||
| 170896c0cc |
@@ -27,8 +27,7 @@ Invoke-ModuleBuild -ModuleName 'GPOZaurr' {
|
||||
}
|
||||
New-ConfigurationManifest @Manifest
|
||||
|
||||
New-ConfigurationModule -Type RequiredModule -Name 'PSWriteColor', 'PSSharedGoods', 'ADEssentials' -Guid Auto -Version Latest
|
||||
New-ConfigurationModule -Type RequiredModule -Name "PSWriteHTML" -Guid Auto -Version "1.27.0"
|
||||
New-ConfigurationModule -Type RequiredModule -Name 'PSWriteColor', 'PSSharedGoods', 'ADEssentials', 'PSWriteHTML' -Guid Auto -Version Latest
|
||||
#New-ConfigurationModule -Type ExternalModule -Name 'Microsoft.PowerShell.Utility', 'Microsoft.PowerShell.Management','Microsoft.PowerShell.Security'
|
||||
New-ConfigurationModule -Type ApprovedModule -Name 'PSSharedGoods', 'PSWriteColor', 'Connectimo', 'PSUnifi', 'PSWebToolbox', 'PSMyPassword', 'ADEssentials'
|
||||
|
||||
@@ -210,7 +209,7 @@ Invoke-ModuleBuild -ModuleName 'GPOZaurr' {
|
||||
# configuration for documentation, at the same time it enables documentation processing
|
||||
New-ConfigurationDocumentation -Enable:$false -StartClean -UpdateWhenNew -PathReadme 'Docs\Readme.md' -Path 'Docs'
|
||||
|
||||
#New-ConfigurationImportModule -ImportSelf
|
||||
New-ConfigurationImportModule -ImportSelf
|
||||
|
||||
New-ConfigurationBuild -Enable:$true -SignModule -MergeModuleOnBuild -MergeFunctionsFromApprovedModules -CertificateThumbprint '483292C9E317AA13B07BB7A96AE9D1A5ED9E7703'
|
||||
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
# GPOZaurr Release History
|
||||
|
||||
## Unreleased
|
||||
- Fix `WindowsDefender` content detection for newer ADMX categories by supporting both:
|
||||
- `Windows Components/Windows Defender*`
|
||||
- `Windows Components/Microsoft Defender Antivirus*`
|
||||
- Fix `WindowsDefenderExploitGuard` detection for legacy/new category naming variants.
|
||||
- Add Defender registry fallback parsing (`SOFTWARE\Microsoft\Windows Defender*`) so Defender settings that land in `RegistrySettings` are still surfaced in `WindowsDefender` report output. [#81](https://github.com/EvotecIT/GPOZaurr/issues/81)
|
||||
|
||||
## 1.1.9 - 2024.12.02
|
||||
- Fixes `Invoke-GPOZaurr` when using SplitReports without path [#58](https://github.com/EvotecIT/GPOZaurr/issues/58)
|
||||
|
||||
## 1.1.8 - 2024.11.20
|
||||
### What's new
|
||||
- Added `RestrictedGroups` to GroupAnalysis
|
||||
|
||||
+108
-163
@@ -8,7 +8,7 @@ schema: 2.0.0
|
||||
# Invoke-GPOZaurrContent
|
||||
|
||||
## SYNOPSIS
|
||||
Invokes GPOZaurrContent function to retrieve Group Policy Objects information.
|
||||
{{ Fill in the Synopsis }}
|
||||
|
||||
## SYNTAX
|
||||
|
||||
@@ -17,50 +17,37 @@ Invokes GPOZaurrContent function to retrieve Group Policy Objects information.
|
||||
Invoke-GPOZaurrContent [-Forest <String>] [-ExcludeDomains <String[]>] [-IncludeDomains <String[]>]
|
||||
[-ExtendedForestInformation <IDictionary>] [-Type <String[]>] [-Splitter <String>] [-FullObjects]
|
||||
[-OutputType <String[]>] [-OutputPath <String>] [-Open] [-Online] [-CategoriesOnly] [-SingleObject]
|
||||
[-SkipNormalize] [-SkipCleanup] [-Extended] [-GPOName <String[]>] [-GPOGUID <String[]>]
|
||||
[-ProgressAction <ActionPreference>] [<CommonParameters>]
|
||||
[-SkipNormalize] [-SkipCleanup] [-Extended] [<CommonParameters>]
|
||||
```
|
||||
|
||||
### Local
|
||||
```
|
||||
Invoke-GPOZaurrContent [-GPOPath <String>] [-Type <String[]>] [-Splitter <String>] [-FullObjects]
|
||||
[-OutputType <String[]>] [-OutputPath <String>] [-Open] [-Online] [-CategoriesOnly] [-SingleObject]
|
||||
[-SkipNormalize] [-SkipCleanup] [-Extended] [-ProgressAction <ActionPreference>] [<CommonParameters>]
|
||||
[-SkipNormalize] [-SkipCleanup] [-Extended] [<CommonParameters>]
|
||||
```
|
||||
|
||||
## DESCRIPTION
|
||||
This function retrieves Group Policy Objects information based on the specified parameters.
|
||||
It can search for GPOs in a forest, exclude specific domains, include specific domains, and provide extended forest information.
|
||||
{{ Fill in the Description }}
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### EXAMPLE 1
|
||||
```
|
||||
Invoke-GPOZaurrContent -Forest "Contoso" -IncludeDomains "Domain1", "Domain2" -Type "Security" -OutputType "HTML" -OutputPath "C:\Reports\GPOReport.html"
|
||||
Retrieves security-related Group Policy Objects information for the specified domains and saves the output as an HTML file.
|
||||
### Example 1
|
||||
```powershell
|
||||
PS C:\> {{ Add example code here }}
|
||||
```
|
||||
|
||||
### EXAMPLE 2
|
||||
```
|
||||
Invoke-GPOZaurrContent -GPOPath "CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=Contoso,DC=com" -Type "All" -OutputType "Object"
|
||||
Retrieves all information for a specific Group Policy Object and outputs the result as an object.
|
||||
```
|
||||
|
||||
### EXAMPLE 3
|
||||
```
|
||||
Invoke-GPOZaurrContent -GPOName "Group Policy Test" -SingleObject | ConvertTo-Json -Depth 3
|
||||
Quickly view GPO settings by name in JSON format for easy inspection.
|
||||
```
|
||||
{{ Add example description here }}
|
||||
|
||||
## PARAMETERS
|
||||
|
||||
### -Forest
|
||||
Specifies the forest name to search for Group Policy Objects.
|
||||
### -CategoriesOnly
|
||||
{{ Fill CategoriesOnly Description }}
|
||||
|
||||
```yaml
|
||||
Type: String
|
||||
Parameter Sets: Default
|
||||
Aliases: ForestName
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
@@ -70,7 +57,7 @@ Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -ExcludeDomains
|
||||
Specifies an array of domains to exclude from the search.
|
||||
{{ Fill ExcludeDomains Description }}
|
||||
|
||||
```yaml
|
||||
Type: String[]
|
||||
@@ -84,13 +71,13 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -IncludeDomains
|
||||
Specifies an array of domains to include in the search.
|
||||
### -Extended
|
||||
{{ Fill Extended Description }}
|
||||
|
||||
```yaml
|
||||
Type: String[]
|
||||
Parameter Sets: Default
|
||||
Aliases: Domain, Domains
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
@@ -100,7 +87,7 @@ Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -ExtendedForestInformation
|
||||
Specifies additional information about the forest.
|
||||
{{ Fill ExtendedForestInformation Description }}
|
||||
|
||||
```yaml
|
||||
Type: IDictionary
|
||||
@@ -114,8 +101,38 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Forest
|
||||
{{ Fill Forest Description }}
|
||||
|
||||
```yaml
|
||||
Type: String
|
||||
Parameter Sets: Default
|
||||
Aliases: ForestName
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -FullObjects
|
||||
{{ Fill FullObjects Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -GPOPath
|
||||
Specifies the path to a specific Group Policy Object.
|
||||
{{ Fill GPOPath Description }}
|
||||
|
||||
```yaml
|
||||
Type: String
|
||||
@@ -129,13 +146,13 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Type
|
||||
Specifies the type of information to retrieve.
|
||||
### -IncludeDomains
|
||||
{{ Fill IncludeDomains Description }}
|
||||
|
||||
```yaml
|
||||
Type: String[]
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
Parameter Sets: Default
|
||||
Aliases: Domain, Domains
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
@@ -144,59 +161,14 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Splitter
|
||||
Specifies the delimiter to use for splitting information.
|
||||
|
||||
```yaml
|
||||
Type: String
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: [System.Environment]::NewLine
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -FullObjects
|
||||
Indicates whether to retrieve full objects.
|
||||
### -Online
|
||||
{{ Fill Online Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -OutputType
|
||||
Specifies the type of output (HTML or Object).
|
||||
|
||||
```yaml
|
||||
Type: String[]
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: Object
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -OutputPath
|
||||
Specifies the path to save the output.
|
||||
|
||||
```yaml
|
||||
Type: String
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
@@ -205,7 +177,7 @@ Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Open
|
||||
Indicates whether to open the output after retrieval.
|
||||
{{ Fill Open Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
@@ -214,43 +186,44 @@ Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Online
|
||||
Indicates whether to retrieve information online.
|
||||
### -OutputPath
|
||||
{{ Fill OutputPath Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Type: String
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -CategoriesOnly
|
||||
Indicates whether to retrieve only categories.
|
||||
### -OutputType
|
||||
{{ Fill OutputType Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Type: String[]
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
Accepted values: HTML, Object
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -SingleObject
|
||||
When enabled, returns a single consolidated object per GPO rather than multiple objects for each setting. For example, with drive mappings, instead of returning separate objects for each mapped drive in a GPO, it will return one object containing all drive mappings for that GPO. This affects how the data is structured in the output reports.
|
||||
{{ Fill SingleObject Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
@@ -259,80 +232,19 @@ Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -SkipNormalize
|
||||
Indicates whether to skip normalization.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -SkipCleanup
|
||||
Indicates whether to skip cleanup of the output hashtable. When enabled, empty values in the output hashtable are preserved rather than being removed via Remove-EmptyValue. This parameter affects the final processing step before returning GPO analysis results.
|
||||
{{ Fill SkipCleanup Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Extended
|
||||
When enabled, returns the complete output hashtable containing all GPO analysis data, including both the processed reports and raw categories. By default, only the processed reports are returned. This parameter is useful for debugging or when you need access to the underlying data structure.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -GPOName
|
||||
Specifies the name of the Group Policy Object to retrieve. The alias of this parameter is `Name`.
|
||||
|
||||
```yaml
|
||||
Type: String[]
|
||||
Parameter Sets: Default
|
||||
Aliases: Name
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -GPOGUID
|
||||
Specifies one or more Group Policy Object GUIDs to retrieve. This parameter allows you to target specific GPOs by their unique identifier rather than display name.
|
||||
|
||||
|
||||
```yaml
|
||||
Type: String[]
|
||||
Parameter Sets: Default
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
@@ -340,13 +252,43 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -ProgressAction
|
||||
Specifies the action to take when progress is reported.
|
||||
### -SkipNormalize
|
||||
{{ Fill SkipNormalize Description }}
|
||||
|
||||
```yaml
|
||||
Type: ActionPreference
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases: proga
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Splitter
|
||||
{{ Fill Splitter Description }}
|
||||
|
||||
```yaml
|
||||
Type: String
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Type
|
||||
{{ Fill Type Description }}
|
||||
|
||||
```yaml
|
||||
Type: String[]
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
@@ -360,8 +302,11 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable
|
||||
|
||||
## INPUTS
|
||||
|
||||
### None
|
||||
|
||||
## OUTPUTS
|
||||
|
||||
### System.Object
|
||||
## NOTES
|
||||
|
||||
## RELATED LINKS
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force
|
||||
|
||||
|
||||
#$O = Invoke-GPOZaurrContent -GPOName "Test-RestrictedGroups" -Verbose
|
||||
#$O
|
||||
|
||||
Invoke-GPOZaurr -Online -Type GPOBroken, GPOBrokenLink -Verbose -SplitReports
|
||||
|
||||
return
|
||||
|
||||
#$Output = Invoke-GPOZaurrContent -GPOPath 'C:\Support\GitHub\GpoZaurr\Ignore\GPODefender'
|
||||
$Output = Invoke-GPOZaurrContent -GPOPath 'C:\Support\GitHub\GpoZaurr\Ignore\GPOExport' -Type WindowsHelloForBusiness
|
||||
$Output | Format-Table
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#$Objects = Get-GPOZaurrInheritance
|
||||
#$Objects | Format-Table
|
||||
|
||||
# Get same output DN, CanonicalName, BlockInheritance (True/False) + Users/Computers + UsersCount/ComputerCount for those with Blocked Inheritance
|
||||
# Get same output DN, CanonicalName, BlockInheritance (True/False) + Users/Computers + UsersCount/ComputerCount for those with Blocked Inhertiance
|
||||
# This is so you can have a list what machines are affected
|
||||
$ExcludedOU = @(
|
||||
# Works on OU/
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
$OUs = Get-GPOZaurrOrganizationalUnit
|
||||
$Ous | Format-Table
|
||||
|
||||
return
|
||||
|
||||
Get-GPOZaurrOrganizationalUnit -Verbose -Option Unlink -Exclusions @(
|
||||
'OU=Groups,OU=Production,DC=ad,DC=evotec,DC=pl'
|
||||
) | Format-Table
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
Import-Module .\GPOZaurr.psd1 -Force
|
||||
|
||||
$DirectoryPath = "C:\Support\GitHub\GpoZaurr\Data\ADMXTemplates"
|
||||
$Paths = @(
|
||||
[PSCustomObject] @{ Name = "Citrix"; Path = "C:\Program Files (x86)\Citrix\ICA Client\Configuration"; ExportFile = "Citrix" }
|
||||
[PSCustomObject] @{ Name = "Remote Desktop Manager"; Path = "C:\Program Files\Devolutions\Remote Desktop Manager\Policies" ; ExportFile = "Remote Desktop Manager" }
|
||||
[PSCustomObject] @{ Name = "Microsoft Windows 2022 Security Baseline"; Path = "C:\Users\przemyslaw.klys\Downloads\GPO\Windows Server 2022 Security Baseline\Windows Server-2022-Security-Baseline-FINAL\Templates" ; ExportFile = "Windows Server 2022 Security Baseline" }
|
||||
[PSCustomObject] @{ Name = "Microsoft OneDrive"; Path = "C:\Program Files\Microsoft OneDrive\24.216.1027.0003\adm" ; ExportFile = "Microsoft OneDrive" }
|
||||
[PSCustomObject] @{ Name = "Microsoft PowerShell 7 Core"; Path = "C:\Program Files\PowerShell\7" ; ExportFile = "Microsoft PowerShell 7" }
|
||||
[PSCustomObject] @{ Name = "Microsoft Windows 11 (24H2) September 2024"; Path = "C:\Program Files (x86)\Microsoft Group Policy\Windows 11 Sep 2024 Update (24H2)" ; ExportFile = "Microsoft Windows11 24H2 September 2024" }
|
||||
)
|
||||
foreach ($Path in $Paths) {
|
||||
$InitializeGPOZaurrTemplateSplat = @{
|
||||
Path = $Path.Path
|
||||
Name = $Path.Name
|
||||
ExportPath = "$DirectoryPath\$($Path.ExportFile).json"
|
||||
}
|
||||
$List = Initialize-GPOZaurrTemplate @InitializeGPOZaurrTemplateSplat -Verbose
|
||||
}
|
||||
+6
-7
@@ -4,32 +4,31 @@
|
||||
CmdletsToExport = @()
|
||||
CompanyName = 'Evotec'
|
||||
CompatiblePSEditions = @('Desktop')
|
||||
Copyright = '(c) 2011 - 2025 Przemyslaw Klys @ Evotec. All rights reserved.'
|
||||
Copyright = '(c) 2011 - 2024 Przemyslaw Klys @ Evotec. All rights reserved.'
|
||||
Description = 'Group Policy Eater is a PowerShell module that aims to gather information about Group Policies but also allows fixing issues that you may find in them.'
|
||||
FunctionsToExport = @('Add-GPOPermission', 'Add-GPOZaurrPermission', 'Backup-GPOZaurr', 'Clear-GPOZaurrSysvolDFSR', 'ConvertFrom-CSExtension', 'Export-GPOZaurrContent', '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-GPOZaurrMissingFiles', 'Get-GPOZaurrNetLogon', 'Get-GPOZaurrOrganizationalUnit', 'Get-GPOZaurrOwner', 'Get-GPOZaurrPassword', 'Get-GPOZaurrPermission', 'Get-GPOZaurrPermissionAnalysis', 'Get-GPOZaurrPermissionConsistency', 'Get-GPOZaurrPermissionIssue', 'Get-GPOZaurrPermissionRoot', 'Get-GPOZaurrPermissionSummary', 'Get-GPOZaurrRedirect', 'Get-GPOZaurrSysvolDFSR', 'Get-GPOZaurrUpdates', 'Get-GPOZaurrWMI', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrContent', 'Invoke-GPOZaurrPermission', 'Invoke-GPOZaurrSupport', 'New-GPOZaurrWMI', 'Optimize-GPOZaurr', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrBroken', 'Remove-GPOZaurrDuplicateObject', 'Remove-GPOZaurrFolders', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrLinkEmptyOU', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrBrokenLink', 'Repair-GPOZaurrNetLogonOwner', 'Repair-GPOZaurrPermission', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Set-GPOOwner', 'Set-GPOZaurrOwner', 'Set-GPOZaurrStatus', 'Skip-GroupPolicy')
|
||||
FunctionsToExport = @('Add-GPOPermission', 'Add-GPOZaurrPermission', 'Backup-GPOZaurr', 'Clear-GPOZaurrSysvolDFSR', 'ConvertFrom-CSExtension', 'Export-GPOZaurrContent', 'Find-CSExtension', 'Get-GPOZaurr', 'Get-GPOZaurrAD', 'Get-GPOZaurrTemplates', '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-GPOZaurrMissingFiles', 'Get-GPOZaurrNetLogon', 'Get-GPOZaurrOrganizationalUnit', 'Get-GPOZaurrOwner', 'Get-GPOZaurrPassword', 'Get-GPOZaurrPermission', 'Get-GPOZaurrPermissionAnalysis', 'Get-GPOZaurrPermissionConsistency', 'Get-GPOZaurrPermissionIssue', 'Get-GPOZaurrPermissionRoot', 'Get-GPOZaurrPermissionSummary', 'Get-GPOZaurrRedirect', 'Get-GPOZaurrSysvolDFSR', 'Get-GPOZaurrUpdates', 'Get-GPOZaurrWMI', 'Initialize-GPOZaurrTemplate', 'Invoke-GPOZaurr', 'Invoke-GPOZaurrContent', 'Invoke-GPOZaurrPermission', 'Invoke-GPOZaurrSupport', 'New-GPOZaurrWMI', 'Optimize-GPOZaurr', 'Remove-GPOPermission', 'Remove-GPOZaurr', 'Remove-GPOZaurrBroken', 'Remove-GPOZaurrDuplicateObject', 'Remove-GPOZaurrFolders', 'Remove-GPOZaurrLegacyFiles', 'Remove-GPOZaurrLinkEmptyOU', 'Remove-GPOZaurrPermission', 'Remove-GPOZaurrWMI', 'Repair-GPOZaurrBrokenLink', 'Repair-GPOZaurrNetLogonOwner', 'Repair-GPOZaurrPermission', 'Repair-GPOZaurrPermissionConsistency', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles', 'Set-GPOOwner', 'Set-GPOZaurrOwner', 'Set-GPOZaurrStatus', 'Skip-GroupPolicy')
|
||||
GUID = 'f7d4c9e4-0298-4f51-ad77-e8e3febebbde'
|
||||
ModuleVersion = '1.1.10'
|
||||
ModuleVersion = '1.1.9'
|
||||
PowerShellVersion = '5.1'
|
||||
PrivateData = @{
|
||||
PSData = @{
|
||||
ExternalModuleDependencies = @('CimCmdlets', 'Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Utility', 'Microsoft.PowerShell.Security')
|
||||
ProjectUri = 'https://github.com/EvotecIT/GPOZaurr'
|
||||
RequireLicenseAcceptance = $false
|
||||
Tags = @('Windows', 'ActiveDirectory', 'GPO', 'GroupPolicy')
|
||||
}
|
||||
}
|
||||
RequiredModules = @(@{
|
||||
Guid = '0b0ba5c5-ec85-4c2b-a718-874e55a8bc3f'
|
||||
ModuleName = 'PSWriteColor'
|
||||
ModuleVersion = '1.0.3'
|
||||
ModuleVersion = '1.0.1'
|
||||
}, @{
|
||||
Guid = 'ee272aa8-baaa-4edf-9f45-b6d6f7d844fe'
|
||||
ModuleName = 'PSSharedGoods'
|
||||
ModuleVersion = '0.0.312'
|
||||
ModuleVersion = '0.0.300'
|
||||
}, @{
|
||||
Guid = '9fc9fd61-7f11-4f4b-a527-084086f1905f'
|
||||
ModuleName = 'ADEssentials'
|
||||
ModuleVersion = '0.0.267'
|
||||
ModuleVersion = '0.0.226'
|
||||
}, @{
|
||||
Guid = 'a7bdf640-f5cb-4acf-9de0-365b322d245c'
|
||||
ModuleName = 'PSWriteHTML'
|
||||
|
||||
+4
-4
@@ -13,7 +13,7 @@ if ($AssemblyFolders.BaseName -contains 'Standard') {
|
||||
}
|
||||
}
|
||||
$FoundErrors = @(
|
||||
foreach ($Import in @($Assembly)) {
|
||||
Foreach ($Import in @($Assembly)) {
|
||||
try {
|
||||
Add-Type -Path $Import.Fullname -ErrorAction Stop
|
||||
} catch [System.Reflection.ReflectionTypeLoadException] {
|
||||
@@ -35,10 +35,10 @@ $FoundErrors = @(
|
||||
}
|
||||
}
|
||||
#Dot source the files
|
||||
foreach ($Import in @($Private + $Public)) {
|
||||
try {
|
||||
Foreach ($Import in @($Private + $Public)) {
|
||||
Try {
|
||||
. $Import.Fullname
|
||||
} catch {
|
||||
} Catch {
|
||||
Write-Error -Message "Failed to import functions from $($import.Fullname): $_"
|
||||
$true
|
||||
}
|
||||
|
||||
@@ -92,26 +92,7 @@
|
||||
|
||||
#>
|
||||
if ($Value.Value.Element) {
|
||||
[Array] $ElementValues = foreach ($Element in @($Value.Value.Element)) {
|
||||
if (-not $Element) {
|
||||
continue
|
||||
}
|
||||
$ElementName = [string] $Element.Name
|
||||
$ElementData = [string] $Element.Data
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($ElementName) -and ($ElementData -eq '' -or $ElementData -eq '0')) {
|
||||
$ElementName
|
||||
} elseif (-not [string]::IsNullOrWhiteSpace($ElementName) -and -not [string]::IsNullOrWhiteSpace($ElementData) -and $ElementName -ne $ElementData) {
|
||||
"$ElementName ($ElementData)"
|
||||
} elseif (-not [string]::IsNullOrWhiteSpace($ElementData)) {
|
||||
$ElementData
|
||||
} elseif (-not [string]::IsNullOrWhiteSpace($ElementName)) {
|
||||
$ElementName
|
||||
}
|
||||
}
|
||||
if ($ElementValues.Count -gt 0) {
|
||||
$Settings["$SubName"] = $ElementValues -join '; '
|
||||
}
|
||||
$Settings["$SubName"] = $Value.Value.Element.Data -join '; '
|
||||
} elseif ($null -eq $Value.Value.Name) {
|
||||
# Shouldn't happen but lets see
|
||||
Write-Verbose "Tracking $Value"
|
||||
@@ -193,26 +174,7 @@
|
||||
|
||||
#>
|
||||
if ($Value.Value.Element) {
|
||||
[Array] $ElementValues = foreach ($Element in @($Value.Value.Element)) {
|
||||
if (-not $Element) {
|
||||
continue
|
||||
}
|
||||
$ElementName = [string] $Element.Name
|
||||
$ElementData = [string] $Element.Data
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($ElementName) -and ($ElementData -eq '' -or $ElementData -eq '0')) {
|
||||
$ElementName
|
||||
} elseif (-not [string]::IsNullOrWhiteSpace($ElementName) -and -not [string]::IsNullOrWhiteSpace($ElementData) -and $ElementName -ne $ElementData) {
|
||||
"$ElementName ($ElementData)"
|
||||
} elseif (-not [string]::IsNullOrWhiteSpace($ElementData)) {
|
||||
$ElementData
|
||||
} elseif (-not [string]::IsNullOrWhiteSpace($ElementName)) {
|
||||
$ElementName
|
||||
}
|
||||
}
|
||||
if ($ElementValues.Count -gt 0) {
|
||||
$CreateGPO["$SubName"] = $ElementValues -join '; '
|
||||
}
|
||||
$CreateGPO["$SubName"] = $Value.Value.Element.Data -join '; '
|
||||
} elseif ($null -eq $Value.Value.Name) {
|
||||
# Shouldn't happen but lets see
|
||||
Write-Verbose "Tracking $Value"
|
||||
@@ -242,4 +204,4 @@
|
||||
#}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
function ConvertTo-XMLRegistryDefenderOnReport {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Converts Defender-related raw registry settings from the RegistrySettings report.
|
||||
|
||||
.DESCRIPTION
|
||||
This function is used as a fallback for Defender settings that are not exposed as
|
||||
policy categories but are still present in RegistrySettings output.
|
||||
|
||||
.PARAMETER GPO
|
||||
RegistrySettings report object generated by ConvertTo-XMLRegistrySettings -SingleObject.
|
||||
#>
|
||||
[cmdletBinding()]
|
||||
param(
|
||||
[PSCustomObject] $GPO
|
||||
)
|
||||
|
||||
[Array] $RegistrySettings = @()
|
||||
if ($GPO.Settings) {
|
||||
$RegistrySettings = $GPO.Settings
|
||||
} elseif ($GPO.DataSet) {
|
||||
# This path supports direct use from dictionary code where RegistrySettings is not requested explicitly.
|
||||
[Array] $DataSet = $GPO.DataSet
|
||||
if ($DataSet.Count -gt 0 -and (
|
||||
$DataSet[0].PSObject.Properties.Name -contains 'Properties' -or
|
||||
$DataSet[0].PSObject.Properties.Name -contains 'Registry' -or
|
||||
$DataSet[0].PSObject.Properties.Name -contains 'Collection'
|
||||
)
|
||||
) {
|
||||
$RegistrySettings = Get-XMLNestedRegistry -GPO $GPO -DataSet $GPO.DataSet
|
||||
}
|
||||
}
|
||||
|
||||
$UsedNames = [System.Collections.Generic.List[string]]::new()
|
||||
$CreateGPO = [ordered] @{
|
||||
DisplayName = $GPO.DisplayName
|
||||
DomainName = $GPO.DomainName
|
||||
GUID = $GPO.GUID
|
||||
GpoType = $GPO.GpoType
|
||||
}
|
||||
$DefenderSettings = 0
|
||||
|
||||
foreach ($Registry in $RegistrySettings) {
|
||||
if ($Registry.Key -like 'SOFTWARE\Microsoft\Windows Defender*') {
|
||||
$DefenderSettings++
|
||||
$SettingName = if ($Registry.Name) { $Registry.Name } else { $Registry.Key }
|
||||
$PropertyName = Format-ToTitleCase -Text $SettingName -RemoveWhiteSpace -RemoveChar ',', '-', "'", '\(', '\)', ':'
|
||||
|
||||
if ($PropertyName -in $UsedNames) {
|
||||
$UsedNames.Add($PropertyName)
|
||||
$TimesUsed = ($UsedNames | Group-Object | Where-Object { $_.Name -eq $PropertyName }).Count
|
||||
$PropertyName = -join ($PropertyName, "$TimesUsed")
|
||||
} else {
|
||||
$UsedNames.Add($PropertyName)
|
||||
}
|
||||
|
||||
$SettingValue = $Registry.Value
|
||||
if ($null -eq $SettingValue -or "$SettingValue" -eq '') {
|
||||
$SettingValue = $Registry.Name
|
||||
}
|
||||
$CreateGPO[$PropertyName] = $SettingValue
|
||||
|
||||
# Some Defender data can be encoded in either value or value-name depending on setting type.
|
||||
if ($Registry.Name -and "$SettingValue" -ne "$($Registry.Name)") {
|
||||
$CreateGPO["$($PropertyName)ValueName"] = $Registry.Name
|
||||
}
|
||||
if ($Registry.Key) {
|
||||
$CreateGPO["$($PropertyName)RegistryKey"] = $Registry.Key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($DefenderSettings -gt 0) {
|
||||
$CreateGPO['Linked'] = $GPO.Linked
|
||||
$CreateGPO['LinksCount'] = $GPO.LinksCount
|
||||
$CreateGPO['Links'] = $GPO.Links
|
||||
[PSCustomObject] $CreateGPO
|
||||
}
|
||||
}
|
||||
+54
-54
@@ -354,58 +354,58 @@
|
||||
}
|
||||
} else {
|
||||
$GPOOutput = [PsCustomObject] @{
|
||||
'DisplayName' = $XMLContent.GPO.Name
|
||||
'DomainName' = $XMLContent.GPO.Identifier.Domain.'#text'
|
||||
'GUID' = $XMLContent.GPO.Identifier.Identifier.InnerText -replace '{' -replace '}'
|
||||
'Days' = (New-TimeSpan -Start ([DateTime] $XMLContent.GPO.ModifiedTime) -End (Get-Date)).Days
|
||||
'Empty' = $Empty
|
||||
'Linked' = $Linked
|
||||
'Enabled' = $EnabledBool
|
||||
'Optimized' = $Optimized
|
||||
'Problem' = $Problem
|
||||
'ApplyPermission' = $null
|
||||
'Exclude' = $Exclude
|
||||
'SizeMB' = [Math]::Round($TotalSize / 1MB, 2)
|
||||
'Size' = $TotalSize
|
||||
'Description' = $GPO.Description
|
||||
'ComputerPolicies' = $XMLContent.GPO.Computer.ExtensionData.Name -join ", "
|
||||
'UserPolicies' = $XMLContent.GPO.User.ExtensionData.Name -join ", "
|
||||
'FilesCount' = $FilesCount
|
||||
'LinksCount' = $LinksTotalCount
|
||||
'LinksEnabledCount' = $LinksEnabledCount
|
||||
'LinksDisabledCount' = $LinksDisabledCount
|
||||
'EnabledDetails' = $Enabled
|
||||
'ComputerProblem' = $ComputerProblem
|
||||
'ComputerOptimized' = $ComputerOptimized
|
||||
'UserProblem' = $UserProblem
|
||||
'UserOptimized' = $UserOptimized
|
||||
'ComputerSettingsAvailable' = $ComputerSettingsAvailable
|
||||
'UserSettingsAvailable' = $UserSettingsAvailable
|
||||
'DisplayName' = $XMLContent.GPO.Name
|
||||
'DomainName' = $XMLContent.GPO.Identifier.Domain.'#text'
|
||||
'GUID' = $XMLContent.GPO.Identifier.Identifier.InnerText -replace '{' -replace '}'
|
||||
'Days' = (New-TimeSpan -Start ([DateTime] $XMLContent.GPO.ModifiedTime) -End (Get-Date)).Days
|
||||
'Empty' = $Empty
|
||||
'Linked' = $Linked
|
||||
'Enabled' = $EnabledBool
|
||||
'Optimized' = $Optimized
|
||||
'Problem' = $Problem
|
||||
'ApplyPermission' = $null
|
||||
'Exclude' = $Exclude
|
||||
'SizeMB' = [Math]::Round($TotalSize / 1MB, 2)
|
||||
'Size' = $TotalSize
|
||||
'Description' = $GPO.Description
|
||||
'ComputerPolicies' = $XMLContent.GPO.Computer.ExtensionData.Name -join ", "
|
||||
'UserPolicies' = $XMLContent.GPO.User.ExtensionData.Name -join ", "
|
||||
'FilesCount' = $FilesCount
|
||||
'LinksCount' = $LinksTotalCount
|
||||
'LinksEnabledCount' = $LinksEnabledCount
|
||||
'LinksDisabledCount' = $LinksDisabledCount
|
||||
'EnabledDetails' = $Enabled
|
||||
'ComputerProblem' = $ComputerProblem
|
||||
'ComputerOptimized' = $ComputerOptimized
|
||||
'UserProblem' = $UserProblem
|
||||
'UserOptimized' = $UserOptimized
|
||||
'ComputerSettingsAvailable' = $ComputerSettingsAvailable
|
||||
'UserSettingsAvailable' = $UserSettingsAvailable
|
||||
#'ComputerSettingsAvailableReal' = $ComputerSettingsAvailableReal
|
||||
#'UserSettingsAvailableReal' = $UserSettingsAvailableReal
|
||||
'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" }
|
||||
'ComputerSettingsVersionIdentical' = if ($XMLContent.GPO.Computer.VersionDirectory -eq $XMLContent.GPO.Computer.VersionSysvol) { $true } else { $false }
|
||||
'ComputerSettings' = $XMLContent.GPO.Computer.ExtensionData.Extension
|
||||
'UserSettingsStatus' = if ($XMLContent.GPO.User.VersionDirectory -eq 0 -and $XMLContent.GPO.User.VersionSysvol -eq 0) { "NeverModified" } else { "Modified" }
|
||||
'UserSettingsVersionIdentical' = if ($XMLContent.GPO.User.VersionDirectory -eq $XMLContent.GPO.User.VersionSysvol) { $true } else { $false }
|
||||
'UserSettings' = $XMLContent.GPO.User.ExtensionData.Extension
|
||||
'NoSettings' = $NoSettings
|
||||
'CreationTime' = [DateTime] $XMLContent.GPO.CreatedTime
|
||||
'ModificationTime' = [DateTime] $XMLContent.GPO.ModifiedTime
|
||||
'ReadTime' = [DateTime] $XMLContent.GPO.ReadTime
|
||||
'WMIFilter' = $GPO.WmiFilter.name
|
||||
'WMIFilterDescription' = $GPO.WmiFilter.Description
|
||||
'GPODistinguishedName' = $GPO.Path
|
||||
'GPOSysvolPath' = $SysvolGpoPath
|
||||
'SDDL' = if ($Splitter -ne '') { $XMLContent.GPO.SecurityDescriptor.SDDL.'#text' -join $Splitter } else { $XMLContent.GPO.SecurityDescriptor.SDDL.'#text' }
|
||||
'Owner' = $XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text'
|
||||
'OwnerSID' = $XMLContent.GPO.SecurityDescriptor.Owner.SID.'#text'
|
||||
'OwnerType' = $OwnerType
|
||||
'ACL' = @(
|
||||
'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" }
|
||||
'ComputerSetttingsVersionIdentical' = if ($XMLContent.GPO.Computer.VersionDirectory -eq $XMLContent.GPO.Computer.VersionSysvol) { $true } else { $false }
|
||||
'ComputerSettings' = $XMLContent.GPO.Computer.ExtensionData.Extension
|
||||
'UserSettingsStatus' = if ($XMLContent.GPO.User.VersionDirectory -eq 0 -and $XMLContent.GPO.User.VersionSysvol -eq 0) { "NeverModified" } else { "Modified" }
|
||||
'UserSettingsVersionIdentical' = if ($XMLContent.GPO.User.VersionDirectory -eq $XMLContent.GPO.User.VersionSysvol) { $true } else { $false }
|
||||
'UserSettings' = $XMLContent.GPO.User.ExtensionData.Extension
|
||||
'NoSettings' = $NoSettings
|
||||
'CreationTime' = [DateTime] $XMLContent.GPO.CreatedTime
|
||||
'ModificationTime' = [DateTime] $XMLContent.GPO.ModifiedTime
|
||||
'ReadTime' = [DateTime] $XMLContent.GPO.ReadTime
|
||||
'WMIFilter' = $GPO.WmiFilter.name
|
||||
'WMIFilterDescription' = $GPO.WmiFilter.Description
|
||||
'GPODistinguishedName' = $GPO.Path
|
||||
'GPOSysvolPath' = $SysvolGpoPath
|
||||
'SDDL' = if ($Splitter -ne '') { $XMLContent.GPO.SecurityDescriptor.SDDL.'#text' -join $Splitter } else { $XMLContent.GPO.SecurityDescriptor.SDDL.'#text' }
|
||||
'Owner' = $XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text'
|
||||
'OwnerSID' = $XMLContent.GPO.SecurityDescriptor.Owner.SID.'#text'
|
||||
'OwnerType' = $OwnerType
|
||||
'ACL' = @(
|
||||
[PsCustomObject] @{
|
||||
'Name' = $XMLContent.GPO.SecurityDescriptor.Owner.Name.'#text'
|
||||
'Sid' = $XMLContent.GPO.SecurityDescriptor.Owner.SID.'#text'
|
||||
@@ -425,10 +425,10 @@
|
||||
}
|
||||
}
|
||||
)
|
||||
'Auditing' = if ($XMLContent.GPO.SecurityDescriptor.AuditingPresent.'#text' -eq 'true') { $true } else { $false }
|
||||
'Links' = $Links
|
||||
'LinksObjects' = $LinksObjects
|
||||
'GPOObject' = $GPO
|
||||
'Auditing' = if ($XMLContent.GPO.SecurityDescriptor.AuditingPresent.'#text' -eq 'true') { $true } else { $false }
|
||||
'Links' = $Links
|
||||
'LinksObjects' = $LinksObjects
|
||||
'GPOObject' = $GPO
|
||||
}
|
||||
if ($GPOOutput.ACL) {
|
||||
$GPOOutput.ApplyPermission = $false
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
$GPOZaurrBlockedInheritance = [ordered] @{
|
||||
Name = 'Group Policy Blocked Inheritance'
|
||||
Name = 'Group Policy Blocked Inhertiance'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
|
||||
@@ -1169,26 +1169,13 @@
|
||||
Category = 'RegistrySettings'
|
||||
Settings = 'Policy'
|
||||
}
|
||||
@{
|
||||
Category = 'RegistrySettings'
|
||||
Settings = 'RegistrySettings'
|
||||
}
|
||||
)
|
||||
GPOPath = @(
|
||||
'Policies -> Administrative Templates -> Windows Components/Windows Defender'
|
||||
'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus'
|
||||
)
|
||||
GPOPath = 'Policies -> Administrative Templates -> Windows Components/Windows Defender'
|
||||
Code = {
|
||||
@(
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*', 'Windows Components/Microsoft Defender Antivirus*'
|
||||
ConvertTo-XMLRegistryDefenderOnReport -GPO $GPO
|
||||
) | Where-Object { $_ }
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*'
|
||||
}
|
||||
CodeSingle = {
|
||||
@(
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*', 'Windows Components/Microsoft Defender Antivirus*' -SingleObject
|
||||
ConvertTo-XMLRegistryDefenderOnReport -GPO $GPO
|
||||
) | Where-Object { $_ }
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*' -SingleObject
|
||||
}
|
||||
}
|
||||
WindowsDefenderExploitGuard = @{
|
||||
@@ -1199,15 +1186,12 @@
|
||||
Settings = 'Policy'
|
||||
}
|
||||
)
|
||||
GPOPath = @(
|
||||
'Policies -> Administrative Templates -> Windows Components/Windows Defender/Windows Defender Exploit Guard'
|
||||
'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard'
|
||||
)
|
||||
GPOPath = 'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard'
|
||||
Code = {
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*/Windows Defender Exploit Guard*', 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*', 'Windows Components/Microsoft Defender Antivirus/Windows Defender Exploit Guard*'
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*'
|
||||
}
|
||||
CodeSingle = {
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*/Windows Defender Exploit Guard*', 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*', 'Windows Components/Microsoft Defender Antivirus/Windows Defender Exploit Guard*' -SingleObject
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*' -SingleObject
|
||||
}
|
||||
}
|
||||
# WindowsFirewall = @{
|
||||
@@ -1444,4 +1428,4 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Update*', 'Windows Components/Delivery Optimization*' -SingleObject
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
function Get-GPOZaurrTemplates {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
|
||||
)
|
||||
|
||||
|
||||
$SysvolADMXPath = "\\$env:USERDNSDOMAIN\SYSVOL\$env:USERDNSDOMAIN\Policies\PolicyDefinitions"
|
||||
Get-ChildItem -Path $SysvolADMXPath -Filter "*.admx" -Recurse -File | ForEach-Object {
|
||||
[PSCustomObject]@{
|
||||
Name = $_.Name
|
||||
Path = $_.FullName
|
||||
Size = $_.Length
|
||||
LastWriteTime = $_.LastWriteTime
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
function Initialize-GPOZaurrTemplate {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)][string] $Name,
|
||||
[Parameter(Mandatory)][string] $Path,
|
||||
[string] $ExportPath
|
||||
)
|
||||
|
||||
$Files = Get-ChildItem -Path $Path -Filter "*.admx" -Recurse -File
|
||||
$TotalFiles = $Files.Count
|
||||
$ProgressIncrement = [math]::Ceiling($TotalFiles / 10)
|
||||
$CurrentProgress = 0
|
||||
|
||||
$FullList = foreach ($File in $Files) {
|
||||
$CurrentProgress++
|
||||
if ($CurrentProgress % $ProgressIncrement -eq 0) {
|
||||
Write-Verbose ("Initialize-GPOZaurrTemplate - Processing $Name, template file {0} of {1} ({2}%)" -f $CurrentProgress, $TotalFiles, [math]::Round(($CurrentProgress / $TotalFiles) * 100))
|
||||
}
|
||||
$HashInformation = Get-FileHash -LiteralPath $File.FullName
|
||||
$Directories = Get-ChildItem -Path $File.DirectoryName -Directory
|
||||
$Languages = [ordered] @{}
|
||||
foreach ($Directory in $Directories) {
|
||||
$LanguageFile = [io.path]::Combine($Directory.FullName, $File.BaseName + ".adml")
|
||||
$Item = Get-Item -Path $LanguageFile -ErrorAction SilentlyContinue
|
||||
if (Test-Path -Path $LanguageFile) {
|
||||
$HashInformation = Get-FileHash -LiteralPath $LanguageFile
|
||||
$Languages[$Directory.Name] = [PSCustomObject]@{
|
||||
Name = $Directory.Name
|
||||
Hash = $HashInformation.Hash
|
||||
Algorithm = $HashInformation.Algorithm
|
||||
Size = $Item.Length
|
||||
CreationTimeUtc = $Item.CreationTimeUtc
|
||||
LastWriteTimeUtc = $Item.LastWriteTimeUtc
|
||||
}
|
||||
}
|
||||
}
|
||||
[PSCustomObject] @{
|
||||
Name = $File.Name
|
||||
Hash = $HashInformation.Hash
|
||||
Algorithm = $HashInformation.Algorithm
|
||||
Size = $File.Length
|
||||
LanguagesAvailable = $Languages.Keys
|
||||
LanguagesCount = $Languages.Keys.Count
|
||||
CreationTimeUtc = $File.CreationTimeUtc
|
||||
LastWriteTimeUtc = $File.LastWriteTimeUtc
|
||||
LanguageFile = $Languages
|
||||
}
|
||||
}
|
||||
|
||||
$OutputObject = [PSCustomObject] @{
|
||||
Name = $Name
|
||||
Path = $Path
|
||||
Templates = $FullList
|
||||
}
|
||||
if ($ExportPath) {
|
||||
if ($ExportPath.EndsWith('.xml')) {
|
||||
$ExportType = 'XML'
|
||||
} elseif ($ExportPath.EndsWith('.json')) {
|
||||
$ExportType = 'JSON'
|
||||
} else {
|
||||
$ExportType = 'XML'
|
||||
}
|
||||
if ($ExportType -eq 'XML') {
|
||||
$OutputObject | Export-Clixml -Path $ExportPath -ErrorAction Stop
|
||||
} elseif ($ExportType -eq 'JSON') {
|
||||
$OutputObject | ConvertTo-Json -Depth 10 | Set-Content -Path $ExportPath -ErrorAction Stop
|
||||
} else {
|
||||
Write-Warning "ExportType $ExportType is not supported. Exporting to XML."
|
||||
}
|
||||
}
|
||||
$OutputObject
|
||||
}
|
||||
@@ -126,10 +126,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $FilePath) {
|
||||
$FilePath = Get-FileName -Extension 'html' -Temporary -Name "GpoZaurr"
|
||||
}
|
||||
|
||||
# Build data
|
||||
foreach ($T in $Script:GPOConfiguration.Keys) {
|
||||
if ($Script:GPOConfiguration[$T].Enabled -eq $true) {
|
||||
@@ -205,6 +201,10 @@
|
||||
if (-not $SplitReports) {
|
||||
# Generate pretty HTML
|
||||
$TimeLogHTML = Start-TimeLog
|
||||
if (-not $FilePath) {
|
||||
$FilePath = Get-FileName -Extension 'html' -Temporary
|
||||
}
|
||||
|
||||
New-HTMLReportAll -FilePath $FilePath -Online:$Online -HideHTML:$HideHTML -Type $Type
|
||||
|
||||
$TimeLogEndHTML = Stop-TimeLog -Time $TimeLogHTML -Option OneLiner
|
||||
|
||||
@@ -59,10 +59,6 @@
|
||||
Invoke-GPOZaurrContent -GPOPath "CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=Contoso,DC=com" -Type "All" -OutputType "Object"
|
||||
Retrieves all information for a specific Group Policy Object and outputs the result as an object.
|
||||
|
||||
.EXAMPLE
|
||||
Invoke-GPOZaurrContent -GPOName "Group Policy Test" -SingleObject | ConvertTo-Json -Depth 3
|
||||
Quickly view GPO settings by name in JSON format for easy inspection.
|
||||
|
||||
#>
|
||||
[alias('Find-GPO')]
|
||||
[cmdletBinding(DefaultParameterSetName = 'Default')]
|
||||
@@ -287,39 +283,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($Output['Reports']['WindowsDefender']) {
|
||||
# Defender can be represented by policy categories and raw registry settings.
|
||||
# Merge entries per GPO so fallback fields do not create duplicated-looking rows.
|
||||
$MergedWindowsDefender = [System.Collections.Generic.List[PSCustomObject]]::new()
|
||||
$GroupedWindowsDefender = $Output['Reports']['WindowsDefender'] | Group-Object -Property DisplayName, DomainName, GUID, GpoType
|
||||
foreach ($Group in $GroupedWindowsDefender) {
|
||||
$MergedObject = [ordered] @{}
|
||||
foreach ($Entry in $Group.Group) {
|
||||
foreach ($Property in $Entry.PSObject.Properties) {
|
||||
if (-not $MergedObject.Contains($Property.Name)) {
|
||||
$MergedObject[$Property.Name] = $Property.Value
|
||||
} else {
|
||||
$CurrentValue = $MergedObject[$Property.Name]
|
||||
$CurrentEmpty = $null -eq $CurrentValue -or ($CurrentValue -is [string] -and $CurrentValue -eq '')
|
||||
$NewEmpty = $null -eq $Property.Value -or ($Property.Value -is [string] -and $Property.Value -eq '')
|
||||
if ($CurrentEmpty -and -not $NewEmpty) {
|
||||
$MergedObject[$Property.Name] = $Property.Value
|
||||
} elseif (-not $CurrentEmpty -and -not $NewEmpty -and "$CurrentValue" -ne "$($Property.Value)") {
|
||||
$PropertyCounter = 2
|
||||
$AlternativeName = -join ($Property.Name, "$PropertyCounter")
|
||||
while ($MergedObject.Contains($AlternativeName)) {
|
||||
$PropertyCounter++
|
||||
$AlternativeName = -join ($Property.Name, "$PropertyCounter")
|
||||
}
|
||||
$MergedObject[$AlternativeName] = $Property.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$MergedWindowsDefender.Add([PSCustomObject] $MergedObject)
|
||||
}
|
||||
$Output['Reports']['WindowsDefender'] = $MergedWindowsDefender
|
||||
}
|
||||
# Normalize - meaning that before we return each GPO report we make sure that each entry has the same column names regardless which one is first.
|
||||
# Normally if you would have a GPO with just 2 entries for given subject (say LAPS), and then another GPO having 5 settings for the same type
|
||||
# and you would display them one after another - all entries would be shown using first object which has less properties then 2nd or 3rd object
|
||||
@@ -385,4 +348,4 @@
|
||||
|
||||
$Script:GPODitionary.Keys | Sort-Object | Where-Object { $_ -like "*$wordToComplete*" }
|
||||
}
|
||||
Register-ArgumentCompleter -CommandName Invoke-GPOZaurrContent -ParameterName Type -ScriptBlock $SourcesAutoCompleter
|
||||
Register-ArgumentCompleter -CommandName Invoke-GPOZaurrContent -ParameterName Type -ScriptBlock $SourcesAutoCompleter
|
||||
@@ -1,134 +0,0 @@
|
||||
Describe 'Defender content detection' {
|
||||
BeforeAll {
|
||||
Import-Module $PSScriptRoot\..\*.psd1 -Force
|
||||
}
|
||||
|
||||
It 'WindowsDefender dictionary supports old and new categories' {
|
||||
InModuleScope GPOZaurr {
|
||||
$Entry = $Script:GPODitionary['WindowsDefender']
|
||||
$Entry.GPOPath | Should -Contain 'Policies -> Administrative Templates -> Windows Components/Windows Defender'
|
||||
$Entry.GPOPath | Should -Contain 'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus'
|
||||
($Entry.Types | Where-Object { $_.Category -eq 'RegistrySettings' -and $_.Settings -eq 'RegistrySettings' }).Count | Should -BeGreaterOrEqual 1
|
||||
$Entry.Code.ToString() | Should -Match 'ConvertTo-XMLRegistryDefenderOnReport'
|
||||
}
|
||||
}
|
||||
|
||||
It 'WindowsDefenderExploitGuard supports category variants' {
|
||||
InModuleScope GPOZaurr {
|
||||
$Entry = $Script:GPODitionary['WindowsDefenderExploitGuard']
|
||||
$Entry.GPOPath | Should -Contain 'Policies -> Administrative Templates -> Windows Components/Windows Defender/Windows Defender Exploit Guard'
|
||||
$Entry.GPOPath | Should -Contain 'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard'
|
||||
$Entry.Code.ToString() | Should -Match 'Windows Components/Microsoft Defender Antivirus/Windows Defender Exploit Guard\*'
|
||||
}
|
||||
}
|
||||
|
||||
It 'ConvertTo-XMLRegistryDefenderOnReport returns only Defender registry settings' {
|
||||
InModuleScope GPOZaurr {
|
||||
$GPO = [PSCustomObject] @{
|
||||
DisplayName = 'Test Defender GPO'
|
||||
DomainName = 'contoso.com'
|
||||
GUID = '11111111-1111-1111-1111-111111111111'
|
||||
GpoType = 'Computer'
|
||||
Linked = $true
|
||||
LinksCount = 1
|
||||
Links = @('OU=Workstations,DC=contoso,DC=com')
|
||||
Settings = @(
|
||||
[PSCustomObject] @{
|
||||
Hive = 'HKEY_LOCAL_MACHINE'
|
||||
Key = 'SOFTWARE\Microsoft\Windows Defender\MpEngine'
|
||||
Name = 'MpFolderScanThreadCount'
|
||||
Type = 'REG_DWORD'
|
||||
Value = '4'
|
||||
Changed = [datetime] '2026-02-18T11:15:00'
|
||||
Filters = $null
|
||||
}
|
||||
[PSCustomObject] @{
|
||||
Hive = 'HKEY_LOCAL_MACHINE'
|
||||
Key = 'SOFTWARE\Contoso\Other'
|
||||
Name = 'Setting'
|
||||
Type = 'REG_SZ'
|
||||
Value = 'Value'
|
||||
Changed = [datetime] '2026-02-18T11:15:00'
|
||||
Filters = $null
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
[Array] $Result = ConvertTo-XMLRegistryDefenderOnReport -GPO $GPO
|
||||
$Result.Count | Should -Be 1
|
||||
$Result[0].MpFolderScanThreadCount | Should -Be '4'
|
||||
$Result[0].MpFolderScanThreadCountRegistryKey | Should -Be 'SOFTWARE\Microsoft\Windows Defender\MpEngine'
|
||||
}
|
||||
}
|
||||
|
||||
It 'ConvertTo-XMLRegistryDefenderOnReport supports raw DataSet input' {
|
||||
InModuleScope GPOZaurr {
|
||||
$GPO = [PSCustomObject] @{
|
||||
DisplayName = 'Test Defender GPO'
|
||||
DomainName = 'contoso.com'
|
||||
GUID = '11111111-1111-1111-1111-111111111111'
|
||||
GpoType = 'Computer'
|
||||
Linked = $true
|
||||
LinksCount = 1
|
||||
Links = @('OU=Workstations,DC=contoso,DC=com')
|
||||
DataSet = ([xml] @"
|
||||
<Root>
|
||||
<Registry changed='2026-02-18T11:15:00' disabled='0'>
|
||||
<Properties action='U' hive='HKEY_LOCAL_MACHINE' key='SOFTWARE\Microsoft\Windows Defender\MpEngine' name='MpFolderScanThreadCount' type='REG_DWORD' value='4' />
|
||||
</Registry>
|
||||
</Root>
|
||||
"@).Root.Registry
|
||||
}
|
||||
|
||||
[Array] $Result = ConvertTo-XMLRegistryDefenderOnReport -GPO $GPO
|
||||
$Result.Count | Should -Be 1
|
||||
$Result[0].MpFolderScanThreadCount | Should -Be '4'
|
||||
$Result[0].MpFolderScanThreadCountRegistryKey | Should -Be 'SOFTWARE\Microsoft\Windows Defender\MpEngine'
|
||||
}
|
||||
}
|
||||
|
||||
It 'ConvertTo-XMLGenericPolicy prefers list item names over zero-only data' {
|
||||
InModuleScope GPOZaurr {
|
||||
[xml] $ListValue = @"
|
||||
<Value>
|
||||
<Element>
|
||||
<Name>C:\PathOne</Name>
|
||||
<Data>0</Data>
|
||||
</Element>
|
||||
<Element>
|
||||
<Name>D:\PathTwo</Name>
|
||||
<Data>0</Data>
|
||||
</Element>
|
||||
</Value>
|
||||
"@
|
||||
|
||||
$GPO = [PSCustomObject] @{
|
||||
DisplayName = 'Test Defender GPO'
|
||||
DomainName = 'contoso.com'
|
||||
GUID = '11111111-1111-1111-1111-111111111111'
|
||||
GpoType = 'Computer'
|
||||
Linked = $true
|
||||
LinksCount = 1
|
||||
Links = @('OU=Workstations,DC=contoso,DC=com')
|
||||
DataSet = @(
|
||||
[PSCustomObject] @{
|
||||
Category = 'Windows Components/Microsoft Defender Antivirus/Exclusions'
|
||||
Name = 'Path Exclusions'
|
||||
State = 'Enabled'
|
||||
ListBox = @(
|
||||
[PSCustomObject] @{
|
||||
Name = 'Path Exclusions'
|
||||
Value = $ListValue.Value
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
$Result = ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Microsoft Defender Antivirus*'
|
||||
$Result.PathExclusionsPathExclusions | Should -Match 'C:\\PathOne'
|
||||
$Result.PathExclusionsPathExclusions | Should -Match 'D:\\PathTwo'
|
||||
$Result.PathExclusionsPathExclusions | Should -Not -Be '0; 0'
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user