DSCResources/SwitchLcmMode/SwitchLcmMode.schema.psm1

configuration SwitchLcmMode
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]

    param (
        [Parameter(Mandatory = $true)]
        [string]
        $SourceMetaMofDir,

        [Parameter()]
        [String]
        $TargetMetaMofDir,

        [Parameter()]
        [String]
        $ConfigurationName
    )

    Import-DscResource -ModuleName PSDesiredStateConfiguration

    $TaskName = 'SwitchLcmMode'

    Script 'switchLcmMode'
    {
        TestScript = {
            $lcm = Get-DscLocalConfigurationManager

            if ($lcm.RefreshMode -eq 'Pull')
            {
                $scheduledTask = Get-ScheduledTask | Where-Object { $_.TaskName -like $using:TaskName }
                if ($null -ne $scheduledTask)
                {
                    Write-Verbose "Delete schedule task '$using:TaskName'."
                    Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
                }

                return $true
            }

            Write-Verbose "Current LCM mode is '$($lcm.RefreshMode)', expected is 'Pull'"
            return $false
        }
        SetScript  = {
            $cfgName = $using:ConfigurationName
            $targetDir = $using:TargetMetaMofDir

            if ([string]::IsNullOrWhiteSpace($cfgName))
            {
                $cfgName = $env:ComputerName
            }

            if ([string]::IsNullOrWhiteSpace($targetDir))
            {
                $targetDir = "$($env:TEMP)\DSC_Config"
            }

            $srcMetaMofPath = "$($using:SourceMetaMofDir)\$($cfgName).meta.mof"

            if (-not (Test-Path $srcMetaMofPath))
            {
                Write-Error "ERROR: New MetaMOF file '$srcMetaMofPath' not found."
                return
            }

            Write-Verbose "Creating target folder '$targetDir'..."
            New-Item -Path $targetDir -ItemType Directory -Force -ErrorAction SilentlyContinue

            Write-Verbose "Copy MetaMOF '$srcMetaMofPath' into target folder..."
            Copy-Item -Path $srcMetaMofPath -Destination $targetDir -Force -ErrorAction Stop

            $scheduledTask = Get-ScheduledTask | Where-Object { $_.TaskName -like $using:TaskName }
            if ($null -ne $scheduledTask)
            {
                Write-Verbose "Delete existing schedule task '$using:TaskName'."
                Unregister-ScheduledTask -TaskName $using:TaskName -Confirm:$false -ErrorAction SilentlyContinue
            }

            Write-Verbose "Create scheduled task '$using:TaskName' to activate new DSC configuration..."

            $scriptCode = @"
            Start-Transcript -Path "`$PSScriptRoot\`$(`$MyInvocation.MyCommand.Name).log" -Append

            try
            {
                `$lcm = Get-DscLocalConfigurationManager -ErrorAction Stop

                `$metaMofPath = `'$targetDir\$cfgName.meta.mof`'

                if( -not (Test-Path `$metaMofPath) )
                {
                    throw "ERROR: Missing LCM configuration file `'`$metaMofPath`'."
                }

                if( `$null -ne `$lcm -and `$lcm.RefreshMode -eq 'Push' )
                {
                    Stop-DscConfiguration -Force -ErrorAction SilentlyContinue

                    Remove-DscConfigurationDocument -Stage Pending -Force
                    Remove-DscConfigurationDocument -Stage Current -Force

                    Set-DscLocalConfigurationManager -Path `'$targetDir`' -ComputerName $cfgName -Force -Verbose

                    Update-DscConfiguration -Wait -Verbose
                }
            }
            catch
            {
                Write-Error "Switch to LCM Pull mode failed with error.`n$_"
            }
            finally
            {
                Stop-Transcript
            }
"@


            $scriptFilePath = "$targetDir\$using:TaskName.ps1"
            $scriptCode | Set-Content -Path $scriptFilePath -Encoding UTF8 -Force

            # skip recreation of existing scheduled task
            if ($null -eq (Get-ScheduledTask $using:TaskName -ErrorAction SilentlyContinue))
            {
                $ta = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -File $scriptFilePath"
                # Start at System Startup and repeat Task every 5 minutes for 12 hours
                $tt1 = New-ScheduledTaskTrigger -AtStartup -RandomDelay (New-TimeSpan -Minutes 6)
                $tt2 = New-ScheduledTaskTrigger -At (Get-Date).AddMinutes(10) -Once -RepetitionInterval (New-TimeSpan -Minutes 5) -RepetitionDuration (New-TimeSpan -Hours 12)
                Register-ScheduledTask $using:TaskName -Action $ta -Trigger @($tt1, $tt2) -User 'System' -Force -ErrorAction Stop

                # Restart system to allow a well defined switch from Push to Pull mode
                $global:DSCMachineStatus = 1
            }
        }
        GetScript  = { return `
            @{
                result = 'N/A'
            }
        }
    }
}