Public/Invoke-ComputerMaintenance.ps1

function Invoke-ComputerMaintenance {
    #Requires -Version 3.0
    #Requires -Modules ResourceLocker

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory)]
        [string]$ComputerName,
        [int]$PreventiveLockTimeout = $ModuleWidePreventiveLockTimeout,
        [System.TimeSpan]$PreventiveLockThreshold = $ModuleWidePreventiveLockThreshold
    )

    $ErrorActionPreference = 'Stop'

    Write-Debug -Message ('ENTER {0}' -f $MyInvocation.MyCommand.Name)

    try {
        Write-Debug -Message ('ENTER TRY {0}' -f $MyInvocation.MyCommand.Name)

        Write-Debug -Message ('$ComputerName = ''{0}''' -f $ComputerName)
        Write-Debug -Message ('$PreventiveLockTimeout = {0}' -f $PreventiveLockTimeout)
        Write-Debug -Message ('$PreventiveLockThreshold: ''{0}''' -f [string]$PreventiveLockThreshold)

        Write-Debug -Message ('$IsMaintenanceAllowed = Test-MaintenanceAllowed -ComputerName ''{0}''' -f $ComputerName)
        $IsMaintenanceAllowed = Test-MaintenanceAllowed -ComputerName $ComputerName
        Write-Debug -Message ('$IsMaintenanceAllowed: ''{0}''' -f $IsMaintenanceAllowed)
        Write-Debug -Message 'if ($IsMaintenanceAllowed)'
        if ($IsMaintenanceAllowed) {
            Write-Debug -Message ('$IsMaintenanceNeeded = Test-MaintenanceNeeded -ComputerName ''{0}''' -f $ComputerName)
            $IsMaintenanceNeeded = Test-MaintenanceNeeded -ComputerName $ComputerName
            Write-Debug -Message ('$IsMaintenanceNeeded: ''{0}''' -f $IsMaintenanceNeeded)
            Write-Debug -Message 'if ($IsMaintenanceNeeded)'
            if ($IsMaintenanceNeeded) {
                Write-Debug -Message '$CallerName = Get-LockCallerName'
                $CallerName = Get-LockCallerName
                Write-Debug -Message ('$CallerName = ''{0}''' -f $CallerName)
                Write-Debug -Message ('$HostLock = Lock-HostResource -ComputerName ''{0}'' -CallerName ''{1}'' -Hard' -f $ComputerName, $CallerName)
                $HostLock = Lock-HostResource -ComputerName $ComputerName -CallerName $CallerName -Hard
                Write-Debug -Message ('$HostLock: ''{0}''' -f [string]$HostLock)
            
                Write-Debug -Message '$InitialDateTime = Get-Date'
                $InitialDateTime = Get-Date
                Write-Debug -Message ('$InitialDateTime: ''{0}''' -f [string]$InitialDateTime)
                do {
                    Write-Debug -Message ('$HostLockedPreventive = Test-HostResourceLock -ComputerName ''{0}'' -Type @(''Generic'', ''File'')' -f $ComputerName)
                    $HostLockedPreventive = Test-HostResourceLock -ComputerName $ComputerName -Type @('Generic', 'File')
                    Write-Debug -Message ('$HostLockedPreventive: ''{0}''' -f [string]$HostLockedPreventive)
                    Write-Debug -Message 'if ($HostLockedPreventive)'
                    if ($HostLockedPreventive) {
                        Write-Debug -Message '$CurrentDateTime = Get-Date'
                        $CurrentDateTime = Get-Date
                        Write-Debug -Message ('$CurrentDateTime: ''{0}''' -f [string]$CurrentDateTime)
                        Write-Debug -Message ('$InitialDateTime: ''{0}''' -f [string]$InitialDateTime)
                        Write-Debug -Message ('$PreventiveLockThreshold: ''{0}''' -f [string]$PreventiveLockThreshold)
                        Write-Debug -Message '$PreventiveLockDateTimeThreshold = $InitialDateTime + $PreventiveLockThreshold'
                        $PreventiveLockDateTimeThreshold = $InitialDateTime + $PreventiveLockThreshold
                        Write-Debug -Message ('$PreventiveLockDateTimeThreshold: ''{0}''' -f [string]$PreventiveLockDateTimeThreshold)
                        Write-Debug -Message 'if ($CurrentDateTime -gt $PreventiveLockDateTimeThreshold)'
                        if ($CurrentDateTime -gt $PreventiveLockDateTimeThreshold) {
                            $Message = ('Computer {0} is locked by other sources for more than {1} already' -f $ComputerName, [string]$PreventiveLockThreshold)
                            $PSCmdlet.ThrowTerminatingError((New-Object -TypeName 'System.Management.Automation.ErrorRecord' -ArgumentList ((New-Object -TypeName 'System.TimeoutException' -ArgumentList $Message), 'TimeoutException', [System.Management.Automation.ErrorCategory]::OperationTimeout, $null)))
                        }
                        else {
                            Write-Debug -Message ('Start-Sleep -Seconds {0}' -f $PreventiveLockTimeout)
                            Start-Sleep -Seconds $PreventiveLockTimeout
                        }
                    }
                    Write-Debug -Message 'while ($HostLockedPreventive)'
                }
                while ($HostLockedPreventive)

                Write-Debug -Message ('$PreClearVariables = Invoke-CustomScriptBlockCommand -Mode ''PreClear'' -ComputerName ''{0}'' -Variables (Get-Variable | Where-Object -FilterScript {{$_ -is [System.Management.Automation.PSVariable]}})' -f $ComputerName)
                $PreClearVariables = Invoke-CustomScriptBlockCommand -Mode 'PreClear' -ComputerName $ComputerName -Variables (Get-Variable | Where-Object -FilterScript {$_ -is [System.Management.Automation.PSVariable]})
                Write-Debug -Message ('$PreClearVariables: ''{0}''' -f [string]$PreClearVariables)
                Write-Debug -Message 'if ($PreClearVariables)'
                if ($PreClearVariables) {
                    foreach ($PreClearVariable in $PreClearVariables) {
                        Write-Debug -Message ('$PreClearVariable: ''{0}''' -f [string]$PreClearVariable)
                        Write-Debug -Message ('Set-Variable -Name ''{0}'' -Value ''{1}''' -f $PreClearVariable.Name, [string]$PreClearVariable.Value)
                        Set-Variable -Name $PreClearVariable.Name -Value $PreClearVariable.Value
                    }
                }

                Write-Debug -Message '$DestinationHostLock = $null'
                $DestinationHostLock = $null
                Write-Debug -Message ('$ComputerWorkload = Clear-ComputerWorkload -ComputerName {0} -DestinationHostLock {1}' -f $ComputerName, $DestinationHostLock)
                $ComputerWorkload = Clear-ComputerWorkload -ComputerName $ComputerName -DestinationHostLock ([ref]$DestinationHostLock)
                Write-Debug -Message ('$ComputerWorkload: ''{0}''' -f [string]$ComputerWorkload)
                Write-Debug -Message ('$DestinationHostLock: ''{0}''' -f $DestinationHostLock)

                Write-Debug -Message ('$PostClearVariables = Invoke-CustomScriptBlockCommand -Mode ''PostClear'' -ComputerName ''{0}'' -Variables (Get-Variable | Where-Object -FilterScript {{$_ -is [System.Management.Automation.PSVariable]}})' -f $ComputerName)
                $PostClearVariables = Invoke-CustomScriptBlockCommand -Mode 'PostClear' -ComputerName $ComputerName -Variables (Get-Variable | Where-Object -FilterScript {$_ -is [System.Management.Automation.PSVariable]})
                Write-Debug -Message ('$PostClearVariables: ''{0}''' -f [string]$PostClearVariables)
                Write-Debug -Message 'if ($PostClearVariables)'
                if ($PostClearVariables) {
                    foreach ($PostClearVariable in $PostClearVariables) {
                        Write-Debug -Message ('$PostClearVariable: ''{0}''' -f [string]$PostClearVariable)
                        Write-Debug -Message ('Set-Variable -Name ''{0}'' -Value ''{1}''' -f $PostClearVariable.Name, [string]$PostClearVariable.Value)
                        Set-Variable -Name $PostClearVariable.Name -Value $PostClearVariable.Value
                    }
                }
            
                Write-Debug -Message ('Start-Maintenance -ComputerName ''{0}''' -f $ComputerName)
                Start-Maintenance -ComputerName $ComputerName
                Write-Debug -Message ('Set-MaintenanceState -ComputerName ''{0}''' -f $ComputerName)
                Set-MaintenanceState -ComputerName $ComputerName
                Write-Debug -Message ('$TestComputerResult = Test-Computer -ComputerName ''{0}''' -f $ComputerName)
                $TestComputerResult = Test-Computer -ComputerName $ComputerName
                Write-Debug -Message ('$TestComputerResult = ''{0}''' -f $TestComputerResult)
                Write-Debug -Message 'if ($TestComputerResult)'
                if ($TestComputerResult) {
                    Write-Debug -Message ('$PreRestoreVariables = Invoke-CustomScriptBlockCommand -Mode ''PreRestore'' -ComputerName ''{0}'' -Variables (Get-Variable | Where-Object -FilterScript {{$_ -is [System.Management.Automation.PSVariable]}})' -f $ComputerName)
                    $PreRestoreVariables = Invoke-CustomScriptBlockCommand -Mode 'PreRestore' -ComputerName $ComputerName -Variables (Get-Variable | Where-Object -FilterScript {$_ -is [System.Management.Automation.PSVariable]})
                    Write-Debug -Message ('$PreRestoreVariables: ''{0}''' -f [string]$PreRestoreVariables)
                    Write-Debug -Message 'if ($PreRestoreVariables)'
                    if ($PreRestoreVariables) {
                        foreach ($PreRestoreVariable in $PreRestoreVariables) {
                            Write-Debug -Message ('$PreRestoreVariable: ''{0}''' -f [string]$PreRestoreVariable)
                            Write-Debug -Message ('Set-Variable -Name ''{0}'' -Value ''{1}''' -f $PreRestoreVariable.Name, [string]$PreRestoreVariable.Value)
                            Set-Variable -Name $PreRestoreVariable.Name -Value $PreRestoreVariable.Value
                        }
                    }

                    Write-Debug -Message '$ComputerWorkload = $ComputerWorkload | Select-Object -Unique'
                    $ComputerWorkload = $ComputerWorkload | Select-Object -Unique
                    Write-Debug -Message 'if ($ComputerWorkload -or $ComputerWorkload -is [System.Array])'
                    if ($ComputerWorkload -or $ComputerWorkload -is [System.Array]) {
                        Write-Debug -Message ('Restore-ComputerWorkload -ComputerName ''{0}''' -f $ComputerName)
                        Restore-ComputerWorkload -ComputerName $ComputerName -DestinationHostLock ([ref]$DestinationHostLock)
                    }

                    Write-Debug -Message ('$PostRestoreVariables = Invoke-CustomScriptBlockCommand -Mode ''PostRestore'' -ComputerName ''{0}'' -Variables (Get-Variable | Where-Object -FilterScript {{$_ -is [System.Management.Automation.PSVariable]}})' -f $ComputerName)
                    $PostRestoreVariables = Invoke-CustomScriptBlockCommand -Mode 'PostRestore' -ComputerName $ComputerName -Variables (Get-Variable | Where-Object -FilterScript {$_ -is [System.Management.Automation.PSVariable]})
                    Write-Debug -Message ('$PostRestoreVariables: ''{0}''' -f [string]$PostRestoreVariables)
                    Write-Debug -Message 'if ($PostRestoreVariables)'
                    if ($PostRestoreVariables) {
                        foreach ($PostRestoreVariable in $PostRestoreVariables) {
                            Write-Debug -Message ('$PostRestoreVariable: ''{0}''' -f [string]$PostRestoreVariable)
                            Write-Debug -Message ('Set-Variable -Name ''{0}'' -Value ''{1}''' -f $PostRestoreVariable.Name, [string]$PostRestoreVariable.Value)
                            Set-Variable -Name $PostRestoreVariable.Name -Value $PostRestoreVariable.Value
                        }
                    }
                }
                else {
                    $Message = 'Test-Computer ended unsuccessfully against {0}' -f $ComputerName
                    $PSCmdlet.ThrowTerminatingError((New-Object -TypeName 'System.Management.Automation.ErrorRecord' -ArgumentList ((New-Object -TypeName 'System.SystemException' -ArgumentList $Message), 'SystemException', [System.Management.Automation.ErrorCategory]::InvalidResult, $null)))
                }
            }
        }

        Write-Debug -Message ('EXIT TRY {0}' -f $MyInvocation.MyCommand.Name)
    }
    catch {
        Write-Debug -Message ('ENTER CATCH {0}' -f $MyInvocation.MyCommand.Name)

        Write-Debug -Message ('{0}: $PSCmdlet.ThrowTerminatingError($_)' -f $MyInvocation.MyCommand.Name)
        $PSCmdlet.ThrowTerminatingError($_)

        Write-Debug -Message ('EXIT CATCH {0}' -f $MyInvocation.MyCommand.Name)
    }
    finally {
        Write-Debug -Message ('ENTER FINALLY {0}' -f $MyInvocation.MyCommand.Name)

        Write-Debug -Message ('$FinallyVariables = Invoke-CustomScriptBlockCommand -Mode ''Finally'' -ComputerName ''{0}'' -Variables (Get-Variable | Where-Object -FilterScript {{$_ -is [System.Management.Automation.PSVariable]}})' -f $ComputerName)
        $FinallyVariables = Invoke-CustomScriptBlockCommand -ComputerName $ComputerName -Mode 'Finally' -Variables (Get-Variable | Where-Object -FilterScript {$_ -is [System.Management.Automation.PSVariable]})
        Write-Debug -Message ('$FinallyVariables: ''{0}''' -f [string]$FinallyVariables)
        Write-Debug -Message 'if ($FinallyVariables)'
        if ($FinallyVariables) {
            foreach ($FinallyVariable in $FinallyVariables) {
                Write-Debug -Message ('$FinallyVariable: ''{0}''' -f [string]$FinallyVariable)
                Write-Debug -Message ('Set-Variable -Name ''{0}'' -Value ''{1}''' -f $FinallyVariable.Name, [string]$ErrorHandlingVariable.Value)
                Set-Variable -Name $FinallyVariable.Name -Value $FinallyVariable.Value
            }
        }

        Write-Debug -Message 'if ($HostLock)'
        if ($HostLock) {
            Write-Debug -Message 'Unlock-Resource -LockObject $HostLock'
            Unlock-Resource -LockObject $HostLock
        }
        Write-Debug -Message 'if ($DestinationHostLock)'
        if ($DestinationHostLock) {
            Write-Debug -Message 'Unlock-Resource -LockObject $DestinationHostLock'
            Unlock-Resource -LockObject $DestinationHostLock
        }

        Write-Debug -Message ('EXIT FINALLY {0}' -f $MyInvocation.MyCommand.Name)
    }

    Write-Debug -Message ('EXIT {0}' -f $MyInvocation.MyCommand.Name)
}