Functions/Set-DryADWmiFilterLink.ps1

# DryActiveDirectory is an AD config module for use with DryDeploy, or by itself.
#.
# Copyright (C) 2021 Bjørn Henrik Formo (bjornhenrikformo@gmail.com)
# LICENSE: https://raw.githubusercontent.com/bjoernf73/DryActiveDirectory/main/LICENSE
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Function Set-DryADWmiFilterLink {
    [CmdletBinding(DefaultParameterSetName='Local')]
    Param (
        [Parameter(Mandatory)]
        [String]
        $GPOName,

        [Parameter(Mandatory)]
        [String]
        $WMIFilterName,

        [Parameter(Mandatory,ParameterSetName='Remote',HelpMessage="PSSession
        to run the script blocks in if Remote execution"
)]
        [PSSession] 
        $PSSession,

        [Parameter(Mandatory,ParameterSetName='Local',HelpMessage="Specify the
        Domain Controller to target in Local Session"
)]
        [String] 
        $DomainController
    )

    If ($PSCmdlet.ParameterSetName -eq 'Remote') {
        $Server = 'localhost'
        ol v @('Session Type','Remote')
        ol v @('Remoting to Domain Controller',$PSSession.ComputerName)
    }
    Else {
        $Server = $DomainController
        ol v @('Session Type','Local')
        ol v @('Using Domain Controller',$Server)
    }

    Try {
        # Test the existence of the GPO and the WMIFilter in AD
        [ScriptBlock]$TestADObjectScriptBlock = {
            Param (
                $Filter,
                $Server
            )
            Try {
                $GetADObjectParams   = @{
                    Filter      = $Filter
                    Server      = $Server
                    ErrorAction = 'Stop'
                    
                }
                $ADObject = $Null
                $ADObject = Get-ADObject @GetADObjectParams
                If ($Null -eq $ADObject) {
                    Throw "Object not found"
                }
                $True
            }
            Catch {
                Throw $_
            }
        }
    
        $Filters = @{
            GPO       = "(ObjectClass -eq 'groupPolicyContainer') -and (displayname -eq '$GPOName')"
            WMIFilter = "(ObjectClass -eq 'msWMI-Som') -and (msWMI-name -eq '$WMIFilterName')" 
        }
    
        $Filters.Keys.ForEach({
            $Filter = $Filters["$_"]
            ol v "Searching for filter","$Filter"
            $TestArgumentList = @($Filters["$_"],$Server)
            $InvokeTestParams = @{
                ScriptBlock   = $TestADObjectScriptBlock
                ArgumentList  = $TestArgumentList
            }
            If ($PSCmdlet.ParameterSetName -eq 'Remote') {
                $InvokeTestParams  += @{
                    Session  = $PSSession
                }
            }
            Switch (Invoke-Command @InvokeTestParams) {
                $True {
                    ol v "Verified that '$Filter' returned an object from AD"
                }
                Default {
                    ol v "Failed get '$Filter' in AD"
                    Throw $_
                }
            }
        })

        # If we reached here, the GPO and WMI Filter exist
        [ScriptBlock]$SetScriptBlock = {
            Param (
                $GPOName,
                $WMIFilterName,
                $Server
            )
            Try {
                
                $DomainFQDN = (Get-ADDomain -Server $Server -ErrorAction Stop).DnsRoot
                $GetGPOParams = @{
                    Filter      = "(ObjectClass -eq 'groupPolicyContainer') -and (displayname -eq '$GPOName')"
                    Properties  = @('gPCWQLFilter','ObjectClass')
                    Server      = $Server
                    ErrorAction = 'Stop'
                }
                $GPOADObject = Get-ADObject @GetGPOParams

                $GetWMIFilterParams = @{
                    Filter      = "(ObjectClass -eq 'msWMI-Som') -and (msWMI-name -eq '$WMIFilterName')"
                    Properties  = @('CN','msWMI-name','ObjectClass')
                    Server      = $Server
                    ErrorAction = 'Stop'
                }
                $WMIFilterADObject = Get-ADObject @GetWMIFilterParams
                $gPCWQLFilter = "[$DomainFQDN;$($WMIFilterADObject.CN);0]"

                $SetParams = @{
                    Server      = $Server
                    ErrorAction = 'Stop'
                }
                If ($Null -eq $GPOADObject.gPCWQLFilter) {
                    $SetParams += @{
                        Add = @{gPCWQLFilter=$gPCWQLFilter}
                    }
                }
                Else {
                    $SetParams += @{
                        Replace = @{gPCWQLFilter=$gPCWQLFilter}
                    }
                }

                $GPOADObject | Set-ADObject @SetParams | Out-Null
                $True
            }
            Catch {
                Throw $_
            }
        }
        $SetArgumentList = @($GPOName,$WMIFilterName,$Server)
        $InvokeSetParams = @{
            ScriptBlock   = $SetScriptBlock
            ArgumentList  = $SetArgumentList
        }
        If ($PSCmdlet.ParameterSetName -eq 'Remote') {
            $InvokeSetParams  += @{
                Session  = $PSSession
            }
        }
        $SetResult = Invoke-Command @InvokeSetParams

        Switch ($SetResult) {
            $True {
                ol s "WMIFilter applied to GPO"
                ol v "The WMIFilter '$WMIFilterName' was applied to GPO '$GPOName'"
            }
            Default {
                ol f "WMIFilter not applied to GPO"
                ol e "The WMIFilter '$WMIFilterName' was not applied to GPO '$GPOName': $($SetResult.ToString())"
                Throw $SetResult.ToString()
            }
        }
    }
    Catch {
        $PSCmdlet.ThrowTerminatingError($_)
    }
}