Private/WmiFilterHelpers.ps1
|
<#
WMI filters through ADSI - no third-party module (replaces BW.Utils.GroupPolicy.WMIFilter). A WMI filter is an msWMI-Som object in CN=SOM,CN=WMIPolicy,CN=System,<domain DN>: msWMI-Name the filter name msWMI-Parm1 its description msWMI-Parm2 the queries, encoded below msWMI-ID "{GUID}" (also the object's CN) msWMI-Author, msWMI-CreationDate, msWMI-ChangeDate (yyyyMMddHHmmss.ffffff-000, UTC) msWMI-Parm2 is "<count>;" followed, per query, by "3;10;<query length>;WQL;<namespace>;<query>;". A GPO points at its filter through gPCWQLFilter = "[<dns domain>;{ID};0]". #> function ConvertTo-NSPADWmiParm2 { # PURE. Query strings -> msWMI-Parm2. param([Parameter(Mandatory)][string[]]$Query, [string]$Namespace = 'root\CIMv2') $sb = New-Object Text.StringBuilder [void]$sb.Append("$($Query.Count);") foreach ($q in $Query) { [void]$sb.Append("3;10;$($q.Length);WQL;$Namespace;$q;") } return $sb.ToString() } function ConvertFrom-NSPADWmiParm2 { # PURE. msWMI-Parm2 -> the query strings (namespace dropped). Reads by the encoded lengths, so a # ';' inside a query is safe. param([AllowEmptyString()][string]$Parm2) if ([string]::IsNullOrWhiteSpace($Parm2)) { return @() } $i = $Parm2.IndexOf(';') $count = [int]$Parm2.Substring(0, $i) $pos = $i + 1 $out = New-Object Collections.Generic.List[string] for ($n = 0; $n -lt $count; $n++) { $parts = @() for ($k = 0; $k -lt 5; $k++) { $j = $Parm2.IndexOf(';', $pos); $parts += $Parm2.Substring($pos, $j - $pos); $pos = $j + 1 } $len = [int]$parts[2] $out.Add($Parm2.Substring($pos, $len)) $pos += $len + 1 } return $out.ToArray() } function Get-NSPADWmiSomEntry { # Every msWMI-Som object in the domain as plain objects (Name, Description, Query, Id, DN). param([Parameter(Mandatory)][string]$DomainDN) $root = [ADSI]"LDAP://CN=SOM,CN=WMIPolicy,CN=System,$DomainDN" $searcher = New-Object DirectoryServices.DirectorySearcher($root, '(objectClass=msWMI-Som)') foreach ($p in 'msWMI-Name', 'msWMI-Parm1', 'msWMI-Parm2', 'msWMI-ID', 'distinguishedName') { [void]$searcher.PropertiesToLoad.Add($p) } foreach ($r in $searcher.FindAll()) { [pscustomobject]@{ Name = "$($r.Properties['mswmi-name'])" Description = "$($r.Properties['mswmi-parm1'])" Query = @(ConvertFrom-NSPADWmiParm2 -Parm2 "$($r.Properties['mswmi-parm2'])") Id = "$($r.Properties['mswmi-id'])" DN = "$($r.Properties['distinguishedname'])" } } } function Save-NSPADWmiSomEntry { # Creates (no -DN) or updates (-DN of an existing filter) one msWMI-Som object. param( [Parameter(Mandatory)][string]$DomainDN, [Parameter(Mandatory)][string]$DnsRoot, [Parameter(Mandatory)][string]$Name, [string]$Description, [Parameter(Mandatory)][string[]]$Query, [string]$DN ) $now = (Get-Date).ToUniversalTime().ToString('yyyyMMddHHmmss.ffffff') + '-000' $parm2 = ConvertTo-NSPADWmiParm2 -Query $Query if ($DN) { $entry = [ADSI]"LDAP://$DN" $entry.Put('msWMI-Parm1', $(if ($Description) { $Description } else { ' ' })) $entry.Put('msWMI-Parm2', $parm2) $entry.Put('msWMI-ChangeDate', $now) $entry.SetInfo() return "$DN" } $id = '{' + ([guid]::NewGuid().ToString().ToUpperInvariant()) + '}' $container = [ADSI]"LDAP://CN=SOM,CN=WMIPolicy,CN=System,$DomainDN" $entry = $container.Create('msWMI-Som', "CN=$id") $entry.Put('msWMI-Name', $Name) $entry.Put('msWMI-Parm1', $(if ($Description) { $Description } else { ' ' })) $entry.Put('msWMI-Parm2', $parm2) $entry.Put('msWMI-Author', "$env:USERNAME@$DnsRoot") $entry.Put('msWMI-ID', $id) $entry.Put('instanceType', 4) $entry.Put('showInAdvancedViewOnly', 'TRUE') $entry.Put('msWMI-CreationDate', $now) $entry.Put('msWMI-ChangeDate', $now) $entry.SetInfo() return "CN=$id,CN=SOM,CN=WMIPolicy,CN=System,$DomainDN" } function Set-NSPADGpoWqlFilterAttribute { # Points a GPO (by its {GUID}) at a WMI filter id, or clears it with an empty -WmiFilterId. param([Parameter(Mandatory)][string]$DomainDN, [Parameter(Mandatory)][string]$DnsRoot, [Parameter(Mandatory)][string]$GpoGuid, [AllowEmptyString()][string]$WmiFilterId) $entry = [ADSI]"LDAP://CN={$($GpoGuid.Trim('{}'))},CN=Policies,CN=System,$DomainDN" if ($WmiFilterId) { $entry.Put('gPCWQLFilter', "[$DnsRoot;$WmiFilterId;0]") } else { $entry.PutEx(1, 'gPCWQLFilter', $null) } $entry.SetInfo() } |