diff --git a/Examples/Example-05-WMIFilters.ps1 b/Examples/Example-05-ListingWMIFilters.ps1 similarity index 100% rename from Examples/Example-05-WMIFilters.ps1 rename to Examples/Example-05-ListingWMIFilters.ps1 diff --git a/Examples/Example-06-RemovingWMIFilters.ps1 b/Examples/Example-06-RemovingWMIFilters.ps1 new file mode 100644 index 0000000..93a3414 --- /dev/null +++ b/Examples/Example-06-RemovingWMIFilters.ps1 @@ -0,0 +1,7 @@ +Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force + +# By default it deletes WMI filter in $Env:USERDNSDOMAIN if no Forest/IncludeDomains/ExcludeDomains are specified +Remove-GPOZaurrWMI -Name 'Test' -WhatIf + +# If we want to remove it from all domains within forest +Remove-GPOZaurrWMI -Name 'Test' -Forest 'ad.evotec.xyz' -WhatIf \ No newline at end of file diff --git a/Examples/Example-07-CreatingWMIFilters.ps1 b/Examples/Example-07-CreatingWMIFilters.ps1 new file mode 100644 index 0000000..4106449 --- /dev/null +++ b/Examples/Example-07-CreatingWMIFilters.ps1 @@ -0,0 +1,10 @@ +Import-Module "$PSScriptRoot\..\GPoZaurr.psd1" -Force + +# By default it creates WMI filter in $Env:USERDNSDOMAIN if no Forest/IncludeDomains/ExcludeDomains are specified +New-GPOZaurrWMI -Query 'select * from Win32_OperatingSystem where Version like "6.0%" and ProductType = "3"' -Name 'Test' -Verbose -Force + +# If you want to force creation of same filter in all domains of a forest (this overwrites set value) +#New-GPOZaurrWMI -Query 'select * from Win32_OperatingSystem where Version like "6.0%" and ProductType = "3"' -Name 'Test' -Verbose -Forest 'ad.evotec.xyz' -WhatIf + +# this will target different forest +#New-GPOZaurrWMI -Query 'select * from Win32_OperatingSystem where Version like "6.0%" and ProductType = "3"' -Name 'Test' -Verbose -Forest 'test.evotec.pl' -WhatIf \ No newline at end of file diff --git a/GPOZaurr.psd1 b/GPOZaurr.psd1 index 8b88782..7ea7073 100644 --- a/GPOZaurr.psd1 +++ b/GPOZaurr.psd1 @@ -5,7 +5,7 @@ CompatiblePSEditions = 'Desktop' Copyright = '(c) 2011 - 2020 Przemyslaw Klys @ Evotec. All rights reserved.' Description = 'Group Policy Eater' - FunctionsToExport = 'Backup-GPOZaurr', 'Get-GPOZaurr', 'Get-GPOZaurrBackupInformation', 'Get-GPOZaurrPassword', 'Get-GPOZaurrWMI', 'Remove-GPOZaurr', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles' + FunctionsToExport = 'Backup-GPOZaurr', 'Get-GPOZaurr', 'Get-GPOZaurrBackupInformation', 'Get-GPOZaurrPassword', 'Get-GPOZaurrWMI', 'New-GPOZaurrWMI', 'Remove-GPOZaurr', 'Remove-GPOZaurrWMI', 'Restore-GPOZaurr', 'Save-GPOZaurrFiles' GUID = 'f7d4c9e4-0298-4f51-ad77-e8e3febebbde' ModuleVersion = '0.0.6' PowerShellVersion = '5.1' @@ -13,13 +13,13 @@ PSData = @{ Tags = 'Windows', 'ActiveDirectory', 'GPO' ProjectUri = 'https://github.com/EvotecIT/GPOZaurr' - ExternalModuleDependencies = 'ActiveDirectory', 'GroupPolicy' + ExternalModuleDependencies = 'ActiveDirectory', 'GroupPolicy', 'CimCmdlets', 'Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Utility' } } RequiredModules = @{ - ModuleVersion = '0.0.133' + ModuleVersion = '0.0.134' ModuleName = 'PSSharedGoods' Guid = 'ee272aa8-baaa-4edf-9f45-b6d6f7d844fe' - }, 'ActiveDirectory', 'GroupPolicy' + }, 'ActiveDirectory', 'GroupPolicy', 'CimCmdlets', 'Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Utility' RootModule = 'GPOZaurr.psm1' } \ No newline at end of file diff --git a/Public/Get-GPOZaurrBackupInformation.ps1 b/Public/Get-GPOZaurrBackupInformation.ps1 index 571170e..50d3dee 100644 --- a/Public/Get-GPOZaurrBackupInformation.ps1 +++ b/Public/Get-GPOZaurrBackupInformation.ps1 @@ -1,30 +1,31 @@ function Get-GPOZaurrBackupInformation { [cmdletBinding()] param( - [string] $BackupFolder + [string[]] $BackupFolder ) Begin { } Process { - if ($BackupFolder) { - if ((Test-Path -LiteralPath "$BackupFolder\manifest.xml")) { - [xml] $Xml = Get-Content -LiteralPath "$BackupFolder\manifest.xml" - [Array] $BackupInformation = $Xml.Backups.BackupInst | ForEach-Object { - [PSCustomObject] @{ - DisplayName = $_.GPODisplayName.'#cdata-section' - Domain = $_.GPODomain.'#cdata-section' - Guid = $_.GPOGUid.'#cdata-section' - DomainGuid = $_.GPODomainGuid.'#cdata-section' - DomainController = $_.GPODomainController.'#cdata-section' - BackupTime = $_.BackupTime.'#cdata-section' - ID = $_.ID.'#cdata-section' - Comment = $_.Comment.'#cdata-section' + foreach ($Folder in $BackupFolder) { + if ($Folder) { + if ((Test-Path -LiteralPath "$Folder\manifest.xml")) { + [xml] $Xml = Get-Content -LiteralPath "$Folder\manifest.xml" + $Xml.Backups.BackupInst | ForEach-Object { + [PSCustomObject] @{ + DisplayName = $_.GPODisplayName.'#cdata-section' + Domain = $_.GPODomain.'#cdata-section' + Guid = $_.GPOGUid.'#cdata-section' + DomainGuid = $_.GPODomainGuid.'#cdata-section' + DomainController = $_.GPODomainController.'#cdata-section' + BackupTime = $_.BackupTime.'#cdata-section' + ID = $_.ID.'#cdata-section' + Comment = $_.Comment.'#cdata-section' + } } + } else { + Write-Warning "Get-GPOZaurrBackupInformation - No backup information available" } - $BackupInformation - } else { - Write-Warning "Get-GPOZaurrBackupInformation - No backup information available" } } } diff --git a/Public/New-GPOZaurrWMi.ps1 b/Public/New-GPOZaurrWMi.ps1 new file mode 100644 index 0000000..fd0b97b --- /dev/null +++ b/Public/New-GPOZaurrWMi.ps1 @@ -0,0 +1,81 @@ +function New-GPOZaurrWMI { + [cmdletBinding(SupportsShouldProcess)] + param( + [parameter(Mandatory)][string] $Name, + [string] $Description = ' ', + [parameter(Mandatory)][string] $Query, + [switch] $SkipQueryCheck, + [switch] $Force, + + [alias('ForestName')][string] $Forest, + [string[]] $ExcludeDomains, + [alias('Domain', 'Domains')][string[]] $IncludeDomains, + [System.Collections.IDictionary] $ExtendedForestInformation + ) + if (-not $Forest -and -not $ExcludeDomains -and -not $IncludeDomains -and -not $ExtendedForestInformation) { + $IncludeDomains = $Env:USERDNSDOMAIN + } + + if (-not $SkipQueryCheck) { + try { + $null = Get-CimInstance -Query $Query -ErrorAction Stop -Verbose:$false + } catch { + Write-Warning "New-GPOZaurrWMI - Query error $($_.Exception.Message). Terminating." + return + } + } + + $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation + foreach ($Domain in $ForestInformation.Domains) { + $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] + $DomainInformation = Get-ADDomain -Server $QueryServer + $defaultNamingContext = $DomainInformation.DistinguishedName + #$defaultNamingContext = (Get-ADRootDSE).defaultnamingcontext + [string] $Author = (([ADSI]"LDAP://").UserPrincipalName).ToString() + [string] $GUID = "{" + ([System.Guid]::NewGuid()) + "}" + + [string] $DistinguishedName = -join ("CN=", $GUID, ",CN=SOM,CN=WMIPolicy,CN=System,", $defaultNamingContext) + $CurrentTime = (Get-Date).ToUniversalTime() + [string] $CurrentDate = -join ( + ($CurrentTime.Year).ToString("0000"), + ($CurrentTime.Month).ToString("00"), + ($CurrentTime.Day).ToString("00"), + ($CurrentTime.Hour).ToString("00"), + ($CurrentTime.Minute).ToString("00"), + ($CurrentTime.Second).ToString("00"), + ".", + ($CurrentTime.Millisecond * 1000).ToString("000000"), + "-000" + ) + + [Array] $ExistingWmiFilter = Get-GPOZaurrWMI -ExtendedForestInformation $ForestInformation -IncludeDomains $Domain -Name $Name + if ($ExistingWmiFilter.Count -eq 0) { + [string] $WMIParm2 = -join ("1;3;10;", $Query.Length.ToString(), ";WQL;root\CIMv2;", $Query , ";") + $OtherAttributes = @{ + "msWMI-Name" = $Name + "msWMI-Parm1" = $Description + "msWMI-Parm2" = $WMIParm2 + "msWMI-Author" = $Author + "msWMI-ID" = $GUID + "instanceType" = 4 + "showInAdvancedViewOnly" = "TRUE" + "distinguishedname" = $DistinguishedName + "msWMI-ChangeDate" = $CurrentDate + "msWMI-CreationDate" = $CurrentDate + } + $WMIPath = -join ("CN=SOM,CN=WMIPolicy,CN=System,", $defaultNamingContext) + + try { + Write-Verbose "New-GPOZaurrWMI - Creating WMI filter $Name in $Domain" + New-ADObject -name $GUID -type "msWMI-Som" -Path $WMIPath -OtherAttributes $OtherAttributes -Server $QueryServer + } catch { + Write-Warning "New-GPOZaurrWMI - Creating GPO filter error $($_.Exception.Message). Terminating." + return + } + } else { + foreach ($_ in $ExistingWmiFilter) { + Write-Warning "New-GPOZaurrWMI - Skipping creation of GPO because name: $($_.Name) guid: $($_.ID) for $($_.Domain) already exists." + } + } + } +} \ No newline at end of file diff --git a/Public/Remove-GPOZaurrWMI.ps1 b/Public/Remove-GPOZaurrWMI.ps1 new file mode 100644 index 0000000..875a221 --- /dev/null +++ b/Public/Remove-GPOZaurrWMI.ps1 @@ -0,0 +1,33 @@ +function Remove-GPOZaurrWMI { + [CmdletBinding(SupportsShouldProcess)] + Param ( + [Guid[]] $Guid, + [string[]] $Name, + + [alias('ForestName')][string] $Forest, + [string[]] $ExcludeDomains, + [alias('Domain', 'Domains')][string[]] $IncludeDomains, + [System.Collections.IDictionary] $ExtendedForestInformation + ) + if (-not $Forest -and -not $ExcludeDomains -and -not $IncludeDomains -and -not $ExtendedForestInformation) { + $IncludeDomains = $Env:USERDNSDOMAIN + } + $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation + foreach ($Domain in $ForestInformation.Domains) { + $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] + [Array] $Objects = @( + if ($Guid) { + Get-GPOZaurrWMI -Guid $Guid -ExtendedForestInformation $ForestInformation -IncludeDomains $Domain + } + if ($Name) { + Get-GPOZaurrWMI -Name $Name -ExtendedForestInformation $ForestInformation -IncludeDomains $Domain + } + ) + $Objects | ForEach-Object -Process { + if ($_.DistinguishedName) { + Write-Verbose "Remove-GPOZaurrWMI - Removing WMI Filter $($_.DistinguishedName)" + Remove-ADObject $_.DistinguishedName -Confirm:$false -Server $QueryServer + } + } + } +} \ No newline at end of file