Public/Invoke-Execution.ps1
function Invoke-Execution { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] [CmdletBinding()] PARAM( [ValidateNotNull()] [ExecutionStep[]]$ExecutionSteps ) Process { # Kontext in dem die Executeationsschritte ausgefuehrt werden. $ExecutionStepContext = [System.Collections.Generic.List[PSVariable]] @() $ExecutionStepContext.Add((New-Object PSVariable -ArgumentList 'ErrorActionPreference', 'Stop')) $ExecutionStepContext.Add((New-Object PSVariable -ArgumentList 'Error', $null)) function Execute ([int]$currentStep) { $step = $ExecutionSteps[$currentStep] $step.Executed = $false $exception = $null $skipped = $false # only execute the step if the precondition is met ($skip --> (-not $execute)) if ($null -ne $step.Precondition) { $skipped = (-not $step.Precondition.Invoke()) } if (-not $skipped) { try { $result = $step.ExecutionAction.InvokeWithContext($null, $ExecutionStepContext) $step.Success = $true } catch { $exception = $_.Exception $step.Success = $false $step.ExecutionError = $_ Write-Warning "$($currentStep) -> '$($step.StepDescription)' produced the following exception:`r`n'$($exception.InnerException.Message)'." if ($step.TerminalError) { Write-Verbose 'This is error is flagged as terminal. Undoing all changes..' $needsRecover = $true } else { Write-Verbose 'Continuing execution as error is non-terminal.' } } } else { $step.Executed = $false $step.Success = $true Write-Host "$($currentStep+[int]1). Skipped: $($step.StepDescription) as precondition is met." -ForegroundColor Gray } if ($needsRecover) { Recover ($currentStep) # Undo Execution } else { $step.Executed = (-not $skipped) if ($currentStep + [int]1 -ge $ExecutionSteps.Count) { Write-Host 'Execution finished successfully.' -ForegroundColor Green ; return } # Last Step Execute ($currentStep + [int]1) # Next Step } } function Recover ([int]$currentStep) { $step = $ExecutionSteps[$currentStep] if ($step.Executed -and $step.RecoverAction) { Write-Host "$($currentStep+[int]1). Undo: $($step.StepDescription)" -ForegroundColor Yellow try { $result = $step.RecoverAction.InvokeWithContext($null, $ExecutionStepContext) if (($result -eq $false) -or ($result.length -and $result[0] -eq $false)) { throw "The step '$($step.RecoverAction.ToString())' returned an invalid result: ($result)." } $step.Recovered = $true } catch { Write-Warning 'The automatic recover action failed. Please undo this step manually.' $step.Recovered = $false Write-Error $_.Exception.Message } } if ($currentStep - [int]1 -lt 0) { Write-Host 'All changes have been undone.'; return } # Last Step Recover ($currentStep - [int]1) # Next Step return } Execute 0 } } |