Public/Copy-WmiInstance.ps1

#region Function Copy-WmiInstance
Function Copy-WmiInstance {
<#
.SYNOPSIS
    This function is used to copy the instances of a WMI class.
.DESCRIPTION
    This function is used to copy the instances of a WMI class to another class.
.PARAMETER ClassPathSource
    Specifies the class to be copied from.
.PARAMETER ClassPathDestination
    Specifies the class to be copied to.
.PARAMETER Property
    Specifies the instance property to copy. If this parameter is not specified all instances are copied.(Optional)
.PARAMETER MatchAll
    This switch is used to specify wether to match all or any of the specified instance properties. If this switch is specified you must enter all data
    present in the desired source class instance in order to have a succesfull match. Default is: $false.
.PARAMETER CreateDestination
    This switch is used to create the destination if it does not exist. Default is: $false.
.EXAMPLE
    Copy-WmiInstance -ClassPathSource 'ROOT\SCCM:SCCMZone' -ClassPathDestination 'ROOT\SCCM:SCCMZoneBlog' -CreateDestination
.EXAMPLE
    [hashtable]$Property = @{ Description = 'SCCMZone WebSite' }
    Copy-WmiInstance -ClassPathSource 'ROOT\SCCM:SCCMZone' -ClassPathDestination 'ROOT\SCCM:SCCMZoneBlog' -Property $Property -CreateDestination
.EXAMPLE
    [hashtable]$Property = @{
        SCCMZoneWebSite = 'https:\SCCM-Zone.com'
        Description = 'SCCMZone WebSite'
    }
    Copy-WmiInstance -ClassPathSource 'ROOT\SCCM:SCCMZone' -ClassPathDestination 'ROOT\SCCM:SCCMZoneBlog' -Property $Property -MatchAll -CreateDestination
.NOTES
    This is a module function and can typically be called directly.
.LINK
    https://sccm-zone.com
.LINK
    https://github.com/JhonnyTerminus/SCCM
#>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true,Position=0)]
        [ValidateNotNullorEmpty()]
        [string]$ClassPathSource,
        [Parameter(Mandatory=$true,Position=1)]
        [ValidateNotNullorEmpty()]
        [string]$ClassPathDestination,
        [Parameter(Mandatory=$false,Position=2)]
        [ValidateNotNullorEmpty()]
        [hashtable]$Property,
        [Parameter(Mandatory=$false,Position=3)]
        [ValidateNotNullorEmpty()]
        [switch]$MatchAll = $false,
        [Parameter(Mandatory=$false,Position=4)]
        [ValidateNotNullorEmpty()]
        [switch]$CreateDestination = $false
    )

    Begin {
        ## Get the name of this function and write header
        [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -CmdletBoundParameters $PSBoundParameters -Header
    }
    Process {
        Try {

            ## Set source and destination paths and name variables
            # Set NamespaceSource
            $NamespaceSource = (Split-Path -Path $ClassPathSource -Qualifier).TrimEnd(':')
            # Set NamespaceDestination
            $NamespaceDestination =  (Split-Path -Path $ClassPathDestination -Qualifier).TrimEnd(':')
            # Set ClassNameSource
            $ClassNameSource = (Split-Path -Path $ClassPathSource -NoQualifier)
            # Set ClassNameDestination
            $ClassNameDestination = (Split-Path -Path $ClassPathDestination -NoQualifier)

            ## Check if the source class exists. If source class does not exist throw an error
            $null = Get-WmiClass -Namespace $NamespaceSource -ClassName $ClassNameSource -ErrorAction 'Stop'

            ## Get the class source properties
            $ClassPropertiesSource = Get-WmiProperty -Namespace $NamespaceSource -ClassName $ClassNameSource -ErrorAction 'SilentlyContinue'

            ## Check if the destination class exists
            $ClassDestinationTest = Get-WmiClass -Namespace $NamespaceDestination -ClassName $ClassNameDestination -ErrorAction 'SilentlyContinue'

            ## Create destination class if specified
            If ((-not $ClassDestinationTest) -and $CreateDestination) {
                $null = Copy-WmiClassQualifier -ClassPathSource $ClassPathSource -ClassPathDestination $ClassPathDestination -CreateDestination -ErrorAction 'Stop'
            }
            ElseIf (-not $ClassDestinationTest) {
                $DestinationClassErr = "Destination [$NamespaceDestination`:$ClassNameDestination] does not exist. Use the -CreateDestination switch to automatically create the destination class."
                Write-Log -Message $DestinationClassErr -Severity 2 -Source ${CmdletName}
                Write-Error -Message $DestinationClassErr -Category 'ObjectNotFound'
            }

            ## Get destination class properties
            $ClassPropertiesDestination = Get-WmiProperty -Namespace $NamespaceDestination -ClassName $ClassNameDestination -ErrorAction 'SilentlyContinue'

            ## Copy class properties from the source class if not present in the destination class
            $ClassPropertiesSource | ForEach-Object {
                If ($_.Name -notin $ClassPropertiesDestination.Name) {
                    # Create property
                    $null = New-WmiProperty -Namespace $NamespaceDestination -ClassName $ClassNameDestination -PropertyName $_.Name -PropertyType $_.CimType
                    # Set qualifier if present
                    If ($_.Qualifiers.Name) {
                        $null = Set-WmiPropertyQualifier -Namespace $NamespaceDestination -ClassName $ClassNameDestination -PropertyName $_.Name -Qualifier @{ Name = $_.Qualifiers.Name; Value = $_.Qualifiers.Value }
                    }
                }
            }

            ## Get source class instances
            $ClassInstancesSource =  Get-WmiInstance -Namespace $NamespaceSource -ClassName $ClassNameSource -ErrorAction 'SilentlyContinue' | Select-Object -Property $ClassPropertiesSource.Name

            ## Initialize $CopyInstance object
            [PSCustomObject]$CopyInstance = @()

            ## Copy instances if thery are present in the source class ignoring any errors
            If ($ClassInstancesSource) {

                # Convert instance to hashtable
                $ClassInstancesSource | ForEach-Object {

                    # Initialize/Reset $InstanceProperty hashtable
                    $InstanceProperty = @{}

                    # Assemble instance property hashtable
                    For ($i = 0; $i -le $($ClassPropertiesSource.Name.Length -1); $i++) {
                        $InstanceProperty += [ordered]@{
                            $($ClassPropertiesSource.Name[$i]) = $_.($ClassPropertiesSource.Name[$i])
                        }
                    }

                    # Initialize $ShouldCopy. This variable will be used to asses wether the instance should be copied or not
                    $ShouldCopy = $true
                    # Convert input property and instance property to copy to custom objects for comparison
                    $InputPropertyObj = [PSCustomObject]$Property
                    $InstancePropertyObj = [PSCustomObject]$InstanceProperty

                    # If Property parameter is specified check if instance Property matches the Input Property. If no match is found set the $ShouldCopy value to $false
                    If ($Property -and $MatchAll) {
                        $ShouldCopy = [boolean]$(Compare-Object -ReferenceObject $InputPropertyObj -DifferenceObject $InstancePropertyObj -Property $ClassPropertiesSource.Name -IncludeEqual -ExcludeDifferent)
                    }
                    ElseIf ($Property) {
                        $ShouldCopy = [boolean]$(Compare-Object -ReferenceObject $InputPropertyObj -DifferenceObject $InstancePropertyObj -IncludeEqual -ExcludeDifferent)
                    }

                    # Check if instance already in destination class
                    $ClassInstanceTest = Get-WmiInstance -Namespace $NamespaceDestination -ClassName $ClassNameDestination -Property $InstanceProperty -ErrorAction 'SilentlyContinue'

                    # Create instance if no instance is found in destination class and $ShouldCopy value is $True
                    If ((-not $ClassInstanceTest) -and $ShouldCopy) {
                        $CopyInstance += New-WmiInstance -Namespace $NamespaceDestination -ClassName $ClassNameDestination -Property $InstanceProperty -ErrorAction 'Stop'
                    }
                    ElseIf (-not $ShouldCopy) {
                        Write-Log -Message "Instance does not match specified input property." -Severity 2 -Source ${CmdletName} -DebugMessage
                    }
                    Else {
                        Write-Log -Message "Instance already in destination class [$NamespaceDestination`:$ClassNameDestination]." -Severity 2 -Source ${CmdletName} -DebugMessage
                    }
                }
            }
            Else {
                Write-Log -Message  "No instances found in source class [$NamespaceSource`:$ClassNameSource]." -Severity 2 -Source ${CmdletName} -DebugMessage
            }
        }
        Catch {
            Write-Log -Message "Failed to copy class instances. `n$(Resolve-Error)" -Severity 3 -Source ${CmdletName}
        }
        Finally {
            Write-Output -InputObject $CopyInstance
        }
    }
    End {
        Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -Footer
    }
}
#endregion