mirror of
https://github.com/EvotecIT/GPOZaurr.git
synced 2026-07-26 20:00:09 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 98e93aa07d | |||
| 707c0ed4b2 | |||
| 3a69d14354 | |||
| 95789953a8 | |||
| 927ae5cd15 | |||
| 26ecff620c | |||
| 4358edfd8f | |||
| 31c7e9d817 | |||
| 6718b35aaf | |||
| 808af75ab9 | |||
| 6745e547a4 | |||
| 642c4844a5 | |||
| cd72f79f85 |
@@ -27,7 +27,8 @@ Invoke-ModuleBuild -ModuleName 'GPOZaurr' {
|
||||
}
|
||||
New-ConfigurationManifest @Manifest
|
||||
|
||||
New-ConfigurationModule -Type RequiredModule -Name 'PSWriteColor', 'PSSharedGoods', 'ADEssentials', 'PSWriteHTML' -Guid Auto -Version Latest
|
||||
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 ExternalModule -Name 'Microsoft.PowerShell.Utility', 'Microsoft.PowerShell.Management','Microsoft.PowerShell.Security'
|
||||
New-ConfigurationModule -Type ApprovedModule -Name 'PSSharedGoods', 'PSWriteColor', 'Connectimo', 'PSUnifi', 'PSWebToolbox', 'PSMyPassword', 'ADEssentials'
|
||||
|
||||
@@ -209,7 +210,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,5 +1,21 @@
|
||||
# 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
|
||||
|
||||
**Full Changelog**: https://github.com/EvotecIT/GPOZaurr/compare/v1.1.7...v1.1.8
|
||||
|
||||
## 1.1.7 - 2024.11.20
|
||||
### What's Changed
|
||||
- Added some additional logging to track down issue
|
||||
|
||||
+221
-166
@@ -8,7 +8,7 @@ schema: 2.0.0
|
||||
# Invoke-GPOZaurrContent
|
||||
|
||||
## SYNOPSIS
|
||||
{{ Fill in the Synopsis }}
|
||||
Invokes GPOZaurrContent function to retrieve Group Policy Objects information.
|
||||
|
||||
## SYNTAX
|
||||
|
||||
@@ -17,92 +17,45 @@ schema: 2.0.0
|
||||
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] [<CommonParameters>]
|
||||
[-SkipNormalize] [-SkipCleanup] [-Extended] [-GPOName <String[]>] [-GPOGUID <String[]>]
|
||||
[-ProgressAction <ActionPreference>] [<CommonParameters>]
|
||||
```
|
||||
|
||||
### Local
|
||||
```
|
||||
Invoke-GPOZaurrContent [-GPOPath <String>] [-Type <String[]>] [-Splitter <String>] [-FullObjects]
|
||||
[-OutputType <String[]>] [-OutputPath <String>] [-Open] [-Online] [-CategoriesOnly] [-SingleObject]
|
||||
[-SkipNormalize] [-SkipCleanup] [-Extended] [<CommonParameters>]
|
||||
[-SkipNormalize] [-SkipCleanup] [-Extended] [-ProgressAction <ActionPreference>] [<CommonParameters>]
|
||||
```
|
||||
|
||||
## DESCRIPTION
|
||||
{{ Fill in the 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.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Example 1
|
||||
```powershell
|
||||
PS C:\> {{ Add example code here }}
|
||||
### 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.
|
||||
```
|
||||
|
||||
{{ Add example description 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.
|
||||
```
|
||||
|
||||
## PARAMETERS
|
||||
|
||||
### -CategoriesOnly
|
||||
{{ Fill CategoriesOnly Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -ExcludeDomains
|
||||
{{ Fill ExcludeDomains Description }}
|
||||
|
||||
```yaml
|
||||
Type: String[]
|
||||
Parameter Sets: Default
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Extended
|
||||
{{ Fill Extended Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -ExtendedForestInformation
|
||||
{{ Fill ExtendedForestInformation Description }}
|
||||
|
||||
```yaml
|
||||
Type: IDictionary
|
||||
Parameter Sets: Default
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Forest
|
||||
{{ Fill Forest Description }}
|
||||
Specifies the forest name to search for Group Policy Objects.
|
||||
|
||||
```yaml
|
||||
Type: String
|
||||
@@ -116,27 +69,12 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -FullObjects
|
||||
{{ Fill FullObjects Description }}
|
||||
### -ExcludeDomains
|
||||
Specifies an array of domains to exclude from the search.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -GPOPath
|
||||
{{ Fill GPOPath Description }}
|
||||
|
||||
```yaml
|
||||
Type: String
|
||||
Parameter Sets: Local
|
||||
Type: String[]
|
||||
Parameter Sets: Default
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
@@ -147,7 +85,7 @@ Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -IncludeDomains
|
||||
{{ Fill IncludeDomains Description }}
|
||||
Specifies an array of domains to include in the search.
|
||||
|
||||
```yaml
|
||||
Type: String[]
|
||||
@@ -161,12 +99,12 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Online
|
||||
{{ Fill Online Description }}
|
||||
### -ExtendedForestInformation
|
||||
Specifies additional information about the forest.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Type: IDictionary
|
||||
Parameter Sets: Default
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
@@ -176,27 +114,12 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Open
|
||||
{{ Fill Open Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -OutputPath
|
||||
{{ Fill OutputPath Description }}
|
||||
### -GPOPath
|
||||
Specifies the path to a specific Group Policy Object.
|
||||
|
||||
```yaml
|
||||
Type: String
|
||||
Parameter Sets: (All)
|
||||
Parameter Sets: Local
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
@@ -206,59 +129,13 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -OutputType
|
||||
{{ Fill OutputType Description }}
|
||||
### -Type
|
||||
Specifies the type of information to retrieve.
|
||||
|
||||
```yaml
|
||||
Type: String[]
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
Accepted values: HTML, Object
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -SingleObject
|
||||
{{ Fill SingleObject Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -SkipCleanup
|
||||
{{ Fill SkipCleanup Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -SkipNormalize
|
||||
{{ Fill SkipNormalize Description }}
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
@@ -268,7 +145,52 @@ Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Splitter
|
||||
{{ Fill Splitter Description }}
|
||||
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.
|
||||
|
||||
```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
|
||||
@@ -282,12 +204,133 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Type
|
||||
{{ Fill Type Description }}
|
||||
### -Open
|
||||
Indicates whether to open the output after retrieval.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Online
|
||||
Indicates whether to retrieve information online.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -CategoriesOnly
|
||||
Indicates whether to retrieve only categories.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: False
|
||||
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.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
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
|
||||
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.
|
||||
|
||||
```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: (All)
|
||||
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
|
||||
@@ -297,16 +340,28 @@ Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -ProgressAction
|
||||
Specifies the action to take when progress is reported.
|
||||
|
||||
```yaml
|
||||
Type: ActionPreference
|
||||
Parameter Sets: (All)
|
||||
Aliases: proga
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### CommonParameters
|
||||
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
|
||||
|
||||
## INPUTS
|
||||
|
||||
### None
|
||||
|
||||
## OUTPUTS
|
||||
|
||||
### System.Object
|
||||
## NOTES
|
||||
|
||||
## RELATED LINKS
|
||||
|
||||
@@ -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 Inhertiance
|
||||
# Get same output DN, CanonicalName, BlockInheritance (True/False) + Users/Computers + UsersCount/ComputerCount for those with Blocked Inheritance
|
||||
# This is so you can have a list what machines are affected
|
||||
$ExcludedOU = @(
|
||||
# Works on OU/
|
||||
|
||||
+6
-5
@@ -4,31 +4,32 @@
|
||||
CmdletsToExport = @()
|
||||
CompanyName = 'Evotec'
|
||||
CompatiblePSEditions = @('Desktop')
|
||||
Copyright = '(c) 2011 - 2024 Przemyslaw Klys @ Evotec. All rights reserved.'
|
||||
Copyright = '(c) 2011 - 2025 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')
|
||||
GUID = 'f7d4c9e4-0298-4f51-ad77-e8e3febebbde'
|
||||
ModuleVersion = '1.1.8'
|
||||
ModuleVersion = '1.1.10'
|
||||
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.1'
|
||||
ModuleVersion = '1.0.3'
|
||||
}, @{
|
||||
Guid = 'ee272aa8-baaa-4edf-9f45-b6d6f7d844fe'
|
||||
ModuleName = 'PSSharedGoods'
|
||||
ModuleVersion = '0.0.300'
|
||||
ModuleVersion = '0.0.312'
|
||||
}, @{
|
||||
Guid = '9fc9fd61-7f11-4f4b-a527-084086f1905f'
|
||||
ModuleName = 'ADEssentials'
|
||||
ModuleVersion = '0.0.226'
|
||||
ModuleVersion = '0.0.267'
|
||||
}, @{
|
||||
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,7 +92,26 @@
|
||||
|
||||
#>
|
||||
if ($Value.Value.Element) {
|
||||
$Settings["$SubName"] = $Value.Value.Element.Data -join '; '
|
||||
[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 '; '
|
||||
}
|
||||
} elseif ($null -eq $Value.Value.Name) {
|
||||
# Shouldn't happen but lets see
|
||||
Write-Verbose "Tracking $Value"
|
||||
@@ -174,7 +193,26 @@
|
||||
|
||||
#>
|
||||
if ($Value.Value.Element) {
|
||||
$CreateGPO["$SubName"] = $Value.Value.Element.Data -join '; '
|
||||
[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 '; '
|
||||
}
|
||||
} elseif ($null -eq $Value.Value.Name) {
|
||||
# Shouldn't happen but lets see
|
||||
Write-Verbose "Tracking $Value"
|
||||
@@ -204,4 +242,4 @@
|
||||
#}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
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" }
|
||||
'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' = @(
|
||||
'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' = @(
|
||||
[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 Inhertiance'
|
||||
Name = 'Group Policy Blocked Inheritance'
|
||||
Enabled = $true
|
||||
ActionRequired = $null
|
||||
Data = $null
|
||||
|
||||
@@ -1169,13 +1169,26 @@
|
||||
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*'
|
||||
@(
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*', 'Windows Components/Microsoft Defender Antivirus*'
|
||||
ConvertTo-XMLRegistryDefenderOnReport -GPO $GPO
|
||||
) | Where-Object { $_ }
|
||||
}
|
||||
CodeSingle = {
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*' -SingleObject
|
||||
@(
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*', 'Windows Components/Microsoft Defender Antivirus*' -SingleObject
|
||||
ConvertTo-XMLRegistryDefenderOnReport -GPO $GPO
|
||||
) | Where-Object { $_ }
|
||||
}
|
||||
}
|
||||
WindowsDefenderExploitGuard = @{
|
||||
@@ -1186,12 +1199,15 @@
|
||||
Settings = 'Policy'
|
||||
}
|
||||
)
|
||||
GPOPath = 'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard'
|
||||
GPOPath = @(
|
||||
'Policies -> Administrative Templates -> Windows Components/Windows Defender/Windows Defender Exploit Guard'
|
||||
'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard'
|
||||
)
|
||||
Code = {
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*'
|
||||
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*'
|
||||
}
|
||||
CodeSingle = {
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*' -SingleObject
|
||||
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
|
||||
}
|
||||
}
|
||||
# WindowsFirewall = @{
|
||||
@@ -1428,4 +1444,4 @@
|
||||
ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Update*', 'Windows Components/Delivery Optimization*' -SingleObject
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -201,10 +205,6 @@
|
||||
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,6 +59,10 @@
|
||||
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')]
|
||||
@@ -283,6 +287,39 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
@@ -348,4 +385,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
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
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