Functions/Invoke-POSHOriginNEW.ps1

function Invoke-POSHOriginNEW {
    <#
        .SYNOPSIS
            Invokes a POSHOrigin configuration directly by calling Invoke-DscResource.
 
            ** THIS IS AN EXPERIMENTAL CMDLET AND MAY BE SIGNIFICANTLY MODIFIED IN FUTURE VERSIONS **
        .DESCRIPTION
            Invokes a POSHOrigin configuration directly by calling Invoke-DscResource. The custom object(s) passed into this function will be
            translated into a hashtable suitable for Invoke-DscResource.
 
            ** THIS IS AN EXPERIMENTAL CMDLET AND MAY BE SIGNIFICANTLY MODIFIED IN FUTURE VERSIONS **
        .PARAMETER InputObject
            One or more custom objects containing the required options for the DSC resource to be provisioned.
        .PARAMETER PrettyPrint
            Parse the verbose output and display in an easier to ready format.
        .PARAMETER WhatIf
            Only execute the TEST functionality of DSC.
 
            NO RESOURCES WILL BE MODIFIED.
        .PARAMETER Confirm
            Prompts you for confirmation before running the cmdlet.
        .PARAMETER PassThru
            Return the result of the DSC run.
        .EXAMPLE
            Compiles and invokes a POSHOrigin configuration. Infrastructure resources defined in $myConfig will be tested for compliance and as
            necessary created, deleted, or modified.
 
            Invoke-POSHOriginNEW -Resource $myConfig -Verbose
        .EXAMPLE
            Compiles and tests a POSHOrigin configuration. This will only test the DSC resources for compliance.
            NO RESOURCES WILL BE CREATED, DELETED, OR MODIFIED
 
            Invoke-POSHOrigin -Resource $myConfig -Verbose -WhatIf
        .EXAMPLE
            Pass the options from the POSHOrigin resource directly to Invoke-DscResource.
 
            $myConfig | Invoke-POSHOriginNEW -NoTranslate -Verbose
    #>

    [cmdletbinding()]
    param(
        [parameter(Mandatory,ValueFromPipeline)]
        [ValidateScript({ $_.PSObject.TypeNames[0] -eq 'POSHOrigin.Resource' })]
        [Alias('Resource')]
        [psobject[]]$InputObject,

        [switch]$PrettyPrint,

        [switch]$WhatIf,

        [switch]$PassThru
    )

    begin {

        $PrettyPrint = $PSBoundParameters.ContainsKey('PrettyPrint')

        # Temporarily disable the PowerShell progress bar
        $oldProgPref = $global:ProgressPreference
        $global:ProgressPreference = 'SilentlyContinue'

        # Start stopwatch
        $sw = [diagnostics.stopwatch]::StartNew()

        $results = @()

        # Used to track DSC resources that have been executed.
        # We'll use this so any dependent resources will only execute
        # if all of their dependencies have.
        # NOTE
        # This doesn't validate that the dependent service is in the desired state. Only that the "Set" function was executed
        $executedResources = @()

        function Invoke-DscResourcePrettyPrint {
            [cmdletbinding()]
            param(
                [string]$ResourceName,

                [string]$Method,

                [hashtable]$params
            )

            $result = $null
            if ($PrettyPrint) {
                Invoke-DscResource -Method $Method @params -OutVariable result 4>&1 | _ConvertDscVerboseOutput | foreach {
                    if (($_.message -ne [string]::Empty) -and ($_.State -ne 'End')) {
                        _WriteResourceStatus -Resource $_.resource -Name $ResourceName -Inner -Message $_.message
                    }
                    if ($_.State -eq 'End' -and $_.Stage -eq 'test') {
                        _WriteResourceStatus -Resource $_.resource -Name $ResourceName -Inner -Message $_.message -Complete
                    }
                }
            } else {
                Invoke-DscResource -Method $Method @params -OutVariable result
            }

            return $result
        }
    }

    process {

        foreach ($item in $InputObject) {

            $result = "" | Select Resource, InDesiredState

            # Derive the resource type and module from the resource properties
            # and try to find the DSC resource
            $module = $item.Resource.Split(':')[0]
            $resource = $item.Resource.Split(':')[1]
            $dscResource = _GetDscResource -module $module -Resource $resource

            if ($dscResource) {

                # Construct resource parameters
                if ($null -eq $item.Options.Ensure) {
                    $item.Options | Add-Member -Type NoteProperty -Name 'Ensure' -Value 'Present'
                }

                # Our params and hash to be splatted to Invoke-DscResource
                $params = @{
                    Name = $dscResource.Name
                    ModuleName = @{
                        ModuleName = $dscResource.ModuleName
                        ModuleVersion = $dscResource.Version
                    }
                    Property = ($item | _ConvertToDscResourceHash -DscResource $dscResource)
                    Verbose = $VerbosePreference
                }

                Write-Debug ($params.Property | Format-List -Property * | Out-String)

                if ($PSBoundParameters.ContainsKey('WhatIf')) {
                    # Just test the resource
                    _WriteResourceStatus -Resource $dscResource.Name -Name $item.Name -Stage Test
                    $testResult = Invoke-DscResourcePrettyPrint -Method Test -params $params

                    if ($PSBoundParameters.ContainsKey('PassThru')) {
                        $result = "" | Select Resource, InDesiredState
                        _WriteResourceStatus -Resource $dscResource.Name -Name $item.Name -Stage Get

                        $getResult = Invoke-DscResourcePrettyPrint -Method Get -Params $params

                        $result.Resource = $getResult
                        $result.InDesiredState = $testResult.InDesiredState
                        $results += $result
                    }
                } else {
                    # Test if this resource has any dependencies and only execute if those have been met.
                    $continue = $true
                    $dependenciesExist = @(($item.DependsOn).Count -gt 0)
                    if ($dependenciesExist) {
                        if ($dependency -inotin $executedResources.Keys) {
                            $continue = $false
                        }
                    } else {
                        $continue = $true
                    }

                    # All dependencies met?
                    if ($continue) {
                        # Test and invoke the resource
                        $testResult = $null
                        _WriteResourceStatus -Resource $dscResource.Name -Name $item.Name -Stage Test

                        $testResult = Invoke-DscResourcePrettyPrint -Method Test -params $params

                        #write-verbose ($testResult | fl * | out-string)

                        if (-Not $testResult.InDesiredState) {
                            _WriteResourceStatus -Resource $dscResource.Name -Name $item.Name -Stage Set
                            try {
                                $setResult = Invoke-DscResourcePrettyPrint -Method Set -params $params
                            } catch {
                                Write-Error -Message 'There was a problem setting the resource'
                                Write-Error -Message "$($_.InvocationInfo.ScriptName)($($_.InvocationInfo.ScriptLineNumber)): $($_.InvocationInfo.Line)"
                                write-Error $_
                            }
                        }
                        # Track the resource as 'executed' for dependent resources
                        $executedResources += $item.FullName
                    } else {
                        Write-Error -Message "Dependencies have not been met for resource $($item.FullName). This resource will not be invoked."
                    }

                    if ($PSBoundParameters.ContainsKey('PassThru')) {
                        _WriteResourceStatus -Resource $dscResource.Name -Name $item.Name -Stage Test

                        $testResult = Invoke-DscResourcePrettyPrint -Method Test -Params $params

                        _WriteResourceStatus -Resource $dscResource.Name -Name $item.Name -Stage Get
                        $getResult = Invoke-DscResourcePrettyPrint -Method Get -Params $params

                        $result.Resource = $getResult
                        $result.InDesiredState = $testResult.InDesiredState
                        $results += $result
                    }
                }
            } else {
                Write-Error -Message "Unable to find DSC resource: $($item.Resource)"
            }
            Write-Host -Object "`n"
        }
    }

    end {
        # Reset the progress bar preference
        $global:ProgressPreference = $oldProgPref

        if ($PSBoundParameters.ContainsKey('PassThru')) {
            $results
        }

        # Stop stopwatch
        Write-Verbose -Message "Command finished in $($sw.Elapsed.TotalSeconds) seconds"
        $sw.stop()
    }
}