Public/Invoke-DSC.ps1

function Invoke-Dsc
{
    <#
.SYNOPSIS
Invokes Dsc resources
 
.DESCRIPTION
Passes PSCustomObjects to Invoke-DscResource by invoking the Test method and
if the Test method fails invokes the Set method.
.PARAMETER Resource
Specifies the PSCustomObject to be passed to Invoke-DscResource
.PARAMETER Retry
Specifies the amount of times to rety when the Local Configuration Manager State is busy.
.PARAMETER Delay
Specifies the amount of seconds between retries when the Local Configuration Manager State is busy.
.EXAMPLE
$r = ConvertTo-Dsc -Path 'c:\Config\NewFile.json'
Invoke-Dsc -Resource $r
.EXAMPLE
$r = ConvertTo-Dsc -Path 'c:\Config\NewFile.json'
Invoke-Dsc -Resource $r -Retry 5 -Dealy 60
 
.NOTES
Wraps around the native Invoke-DscResource cmdlet and invokes them as native Dsc would
by running the test method first and if the test method fails it invokes the set method.
#>

    [CmdletBinding(SupportsShouldProcess = $True)]
    Param
    (
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
        [object[]]$Resource,
        [int]$Retry = 5,
        [int]$Delay = 60
    )

    Begin
    {
        $retryCount = 0
        if ((Get-DscLocalConfigurationManager).LCMState -eq 'Busy')
        {
            do
            {
                $retryCount ++
                Write-Warning "Local Configuration Manager is in progress and must return before Invoke-DscResource can be invoked. Will retry in [$Delay] seconds...Retry [$retryCount/$Retry]"
                Start-Sleep -Seconds $Delay
                $LCMstate = (Get-DscLocalConfigurationManager).LCMState
                if ($retryCount -eq $Retry)
                {
                    throw "Local Configuration Manager is in progress after [$Retry] retries. Use -Force option if available or cancel the current operation."
                }
            } until ($retryCount -eq $Retry -or $LCMstate -eq 'Idle')
        }
    }
    Process
    {
        foreach ($r in $Resource)
        {

            $splat = @{
                Name        = $r.dscResourceName
                Property    = $r.Property
                ErrorAction = 'SilentlyContinue'
            }

            if ($null -ne $r.ModuleVersion)
            {
                $splat.Add('ModuleName', @{ModuleName = $($r.ModuleName); ModuleVersion = $($r.ModuleVersion)})
            }
            else
            {
                if ($r.ModuleName -eq 'PSDesiredStateConfiguration' -and $r.dscResourceName -eq 'File')
                {
                    $splat.Add('ModuleName', $r.ModuleName)
                }
                else
                {
                    $latestVersion = Get-LatestModuleVersion -Name $r.ModuleName
                    $splat.Add('ModuleName', @{ModuleName = $($r.ModuleName); ModuleVersion = $latestVersion})
                }
            }

            Write-Output "[Start Test] [[$($r.dscResourceName)]$($r.ResourceName)]"
            $testResults = Invoke-DscResource @splat -Method Test -ErrorVariable TestError -Verbose:$false

            if ($PSCmdlet.ShouldProcess("Invoking Set Method"))
            {

                if ($TestError)
                {
                    Write-Error ("Failed to Invoke $($r.resourceName)" + ($TestError[0].Exception.Message))
                }
                elseif (($testResults.InDesiredState) -ne $true)
                {
                    Write-Output "[Start Set] [[$($r.dscResourceName)]$($r.ResourceName)]"
                    Invoke-DscResource @splat -Method Set -ErrorVariable SetError -Verbose:$false
                }

                if ($SetError)
                {
                    Write-Error "Failed to invoke [$($r.resourceName)] ($SetError[0].Exception.Message)"
                }

            }

        }
    }
    End
    {
    }
}