MOFCompare.psm1

using namespace System.Collections.Generic
using namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal
function Compare-MOF {
    [cmdletbinding()]
    param(
        [parameter(Mandatory)]
        $ReferenceMOF,

        [parameter(Mandatory, ValueFromPipeline = $true)]
        $DifferencingMOF,

        [parameter()]
        [switch]
        $CompareProperties
    )

    process {
        $CompareResult = Compare-Object $ReferenceMOF.keys.ForEach{ $_ } $DifferencingMOF.keys.ForEach{ $_ } -IncludeEqual -PassThru

        $ReturnObject = [pscustomobject]@{
            Missing = $CompareResult.Where( { $_.SideIndicator -eq "<=" })
            New     = $CompareResult.Where( { $_.SideIndicator -eq "=>" })
            Changed = $null
        }

        if ($CompareProperties.IsPresent) {

            [Dictionary[string, PSCustomObject[]]]$ChangedResources = (New-Object 'System.Collections.Generic.Dictionary[string, PSCustomObject[]]')

            Foreach ($key in $CompareResult.Where( { $_.SideIndicator -eq "==" })) {
                $propertiestocheck = $ConfigurationElements[$key].CimInstanceProperties.name.Where{ $key -notin @("sourceinfo") }
                if (Compare-Object $ConfigurationElements[$key] $ConfigurationElements1[$key] -Property $propertiestocheck) {
                    $changedproperties = @()
                    foreach ($property in $propertiestocheck) {
                        $result = Compare-Object $ConfigurationElements[$key] $ConfigurationElements1[$key] -Property $property
                        if ($result) {
                            $changedproperties += [PSCustomObject]@{
                                Name     = $property
                                NewValue = $result.where( { $_.SideIndicator -eq "=>" }).$property
                                OldValue = $result.where( { $_.SideIndicator -eq "<=" }).$property
                            }
                        }
                    }
                    $ChangedResources.Add($ConfigurationElements[$key].ResourceId, $changedproperties)
                }
            }

            $ReturnObject.Changed = $ChangedResources
        }

        Write-Output $ReturnObject
    }
}

function ConvertFrom-MOF {
    [cmdletbinding()]
    param(
        [Parameter(Mandatory = $true,
            Position = 0,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = "Path to one or more MOFs.")]
        [Alias("PSPath")]
        [ValidateNotNullOrEmpty()]
        [string]
        $Path
    )

    process {
        [Dictionary[Tuple`3[string, string, string], ciminstance]]$ConfigurationElements = (New-Object 'System.Collections.Generic.Dictionary[Tuple`3[string,string,string], ciminstance]')

        [DscClassCache]::ImportInstances((Resolve-Path $Path)) | Foreach-Object -Process {
            trap { $item }
            $item = $_
            if ($_.cimclass.cimclassname -eq "OMI_ConfigurationDocument") {
                $OMIConfig = $_
            } else {
                $KeyValues = $_.CimInstanceProperties.Where{ $_.flags -match 'key' }.Value -join ';'
                $ConfigurationElements.Add(
                    ([Tuple]::Create($_.modulename, $_.cimclass.cimclassname, $KeyValues)),
                    $_
                )
            }
        }

        Write-Output $ConfigurationElements
    }
}
function Initialize-DscResourceCache {
    [cmdletbinding()]
    param(
        [parameter()]
        [string[]]
        $ModulePathsToImport
    )

    begin {
        Reset-DscResourceCache
        $OldPSModulePath = $env:PSModulePath
        if ($ModulePathsToImport.count -gt 0) {
            $env:PSModulePath = $ModulePathsToImport.ForEach{ Resolve-Path $_ } -join ';'
        }
    }

    process {
        Get-Module -ListAvailable | Import-DscResourceToCache -ErrorAction Continue
    }

    end {
        $env:PSModulePath = $OldPSModulePath
    }
}

function Import-DscResourceToCache {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Management.Automation.PSModuleInfo]
        $Module
    )

    begin {
        $errors = New-Object System.Collections.ObjectModel.Collection[Exception]
    }

    process {
        trap { }
        Write-Verbose "Processing module $($Module.Name) $($Module.Version)"

        # script/binary resources
        $importedSchemaFile = ""
        [DscClassCache]::ImportCimKeywordsFromModule($Module, $null, [ref]$importedSchemaFile) | Out-Null

        # class resources
        [DscClassCache]::ImportClassResourcesFromModule($Module, $Module.ExportedDscResources, $null) | Out-Null
    }
}

function Reset-DscResourceCache {
    [cmdletbinding()]
    param()

    process {
        [DscClassCache]::ClearCache()
        [DscClassCache]::LoadDefaultCimKeywords()
    }
}
Export-ModuleMember -Function Compare-MOF,
ConvertFrom-MOF,
Initialize-DscResourceCache