Private/Logic/RuntimeKernel/Execute/Manifested.RuntimeExecution.ps1
|
function Invoke-ManifestedDescriptorRepairStep { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Descriptor, [Parameter(Mandatory = $true)] [hashtable]$CommandOptions ) $facts = Get-ManifestedRuntimeFactsFromContext -Context $Descriptor -LocalRoot $CommandOptions.LocalRoot -FactsCache $(if ($CommandOptions.ContainsKey('FactsCache')) { $CommandOptions['FactsCache'] } else { @{} }) $rawResult = if ($Descriptor.PSObject.Properties['ExecutionModel'] -and $Descriptor.ExecutionModel -eq 'DefinitionBlocks' -and $Descriptor.Definition) { Invoke-ManifestedRuntimeRepairFromDefinition -Definition $Descriptor.Definition -Facts $facts -LocalRoot $CommandOptions.LocalRoot } else { & $Descriptor.RepairFunction -State $facts -LocalRoot $CommandOptions.LocalRoot } return [pscustomobject]@{ Changed = ($rawResult -and $rawResult.PSObject.Properties['Action'] -and ($rawResult.Action -ne 'Skipped')) RestartRequired = $false Result = $rawResult Warnings = @() Dependency = $null } } function Invoke-ManifestedDescriptorEnsureArtifactStep { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Descriptor, [Parameter(Mandatory = $true)] [hashtable]$CommandOptions ) $facts = Get-ManifestedRuntimeFactsFromContext -Context $Descriptor -LocalRoot $CommandOptions.LocalRoot -FactsCache $(if ($CommandOptions.ContainsKey('FactsCache')) { $CommandOptions['FactsCache'] } else { @{} }) $artifact = if ($facts.PSObject.Properties['Package']) { $facts.Package } elseif ($facts.PSObject.Properties['Artifact']) { $facts.Artifact } else { $null } $artifactPath = if ($facts.PSObject.Properties['PackagePath']) { $facts.PackagePath } elseif ($facts.PSObject.Properties['ArtifactPath']) { $facts.ArtifactPath } else { $null } $refreshRequested = [bool]$CommandOptions.RefreshRequested $needsAcquire = $refreshRequested -or [string]::IsNullOrWhiteSpace($artifactPath) if (-not $needsAcquire -and $Descriptor.PSObject.Properties['RequireTrustedArtifact'] -and $Descriptor.RequireTrustedArtifact) { $needsAcquire = -not $facts.ArtifactIsTrusted } if ($needsAcquire) { $artifact = if ($Descriptor.PSObject.Properties['ExecutionModel'] -and $Descriptor.ExecutionModel -eq 'DefinitionBlocks' -and $Descriptor.Definition) { Get-ManifestedSuppliedArtifactFromDefinition -Definition $Descriptor.Definition -RefreshRequested:$refreshRequested -LocalRoot $CommandOptions.LocalRoot } else { $acquireParameters = @{ LocalRoot = $CommandOptions.LocalRoot } if ($Descriptor.PSObject.Properties['ArtifactAcquireRefreshParameterName'] -and -not [string]::IsNullOrWhiteSpace($Descriptor.ArtifactAcquireRefreshParameterName)) { $acquireParameters[$Descriptor.ArtifactAcquireRefreshParameterName] = $refreshRequested } & $Descriptor.EnsureArtifactFunction @acquireParameters } } if ($null -eq $artifact) { throw "The '$($Descriptor.RuntimeName)' artifact could not be resolved." } $validation = if ($Descriptor.PSObject.Properties['ExecutionModel'] -and $Descriptor.ExecutionModel -eq 'DefinitionBlocks' -and $Descriptor.Definition) { Test-ManifestedArtifactTrustFromDefinition -Definition $Descriptor.Definition -Artifact $artifact } else { $validationParameters = @{} $validationParameters[$Descriptor.ArtifactValidationParameterName] = $artifact & $Descriptor.ValidateArtifactFunction @validationParameters } if ($validation -and $validation.PSObject.Properties['CanRepair'] -and $validation.CanRepair) { if ($Descriptor.PSObject.Properties['ExecutionModel'] -and $Descriptor.ExecutionModel -eq 'DefinitionBlocks' -and $Descriptor.Definition) { Invoke-ManifestedRuntimeRepairFromDefinition -Definition $Descriptor.Definition -Facts $facts -CorruptArtifactPaths @($artifact.Path) -LocalRoot $CommandOptions.LocalRoot | Out-Null $artifact = Get-ManifestedSuppliedArtifactFromDefinition -Definition $Descriptor.Definition -RefreshRequested:$true -LocalRoot $CommandOptions.LocalRoot $validation = Test-ManifestedArtifactTrustFromDefinition -Definition $Descriptor.Definition -Artifact $artifact } elseif ($Descriptor.PSObject.Properties['RepairCorruptArtifactParameterName'] -and -not [string]::IsNullOrWhiteSpace($Descriptor.RepairCorruptArtifactParameterName)) { $repairParameters = @{ State = $facts LocalRoot = $CommandOptions.LocalRoot } $repairParameters[$Descriptor.RepairCorruptArtifactParameterName] = @($artifact.Path) & $Descriptor.RepairFunction @repairParameters | Out-Null $reacquireParameters = @{ LocalRoot = $CommandOptions.LocalRoot } if ($Descriptor.PSObject.Properties['ArtifactAcquireRefreshParameterName'] -and -not [string]::IsNullOrWhiteSpace($Descriptor.ArtifactAcquireRefreshParameterName)) { $reacquireParameters[$Descriptor.ArtifactAcquireRefreshParameterName] = $true } $artifact = & $Descriptor.EnsureArtifactFunction @reacquireParameters $validationParameters = @{} $validationParameters[$Descriptor.ArtifactValidationParameterName] = $artifact $validation = & $Descriptor.ValidateArtifactFunction @validationParameters } } if ($validation -and $validation.PSObject.Properties['Exists'] -and -not $validation.Exists) { throw "$($Descriptor.RuntimeName) artifact validation failed because the artifact does not exist." } if ($validation -and $Descriptor.PSObject.Properties['RequireTrustedArtifact'] -and $Descriptor.RequireTrustedArtifact -and $validation.PSObject.Properties['IsTrusted'] -and -not $validation.IsTrusted) { $failureReason = if ($validation.PSObject.Properties['FailureReason']) { $validation.FailureReason } else { 'ArtifactNotTrusted' } throw "$($Descriptor.RuntimeName) artifact validation failed because the artifact is not trusted ($failureReason)." } return [pscustomobject]@{ Changed = [bool]$needsAcquire RestartRequired = $false Result = [pscustomobject]@{ Artifact = $artifact Validation = $validation } Warnings = @() Dependency = $null } } function Invoke-ManifestedDescriptorInstallStep { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Descriptor, [Parameter(Mandatory = $true)] [hashtable]$CommandOptions ) $facts = Get-ManifestedRuntimeFactsFromContext -Context $Descriptor -LocalRoot $CommandOptions.LocalRoot -FactsCache $(if ($CommandOptions.ContainsKey('FactsCache')) { $CommandOptions['FactsCache'] } else { @{} }) $rawResult = if ($Descriptor.PSObject.Properties['ExecutionModel'] -and $Descriptor.ExecutionModel -eq 'DefinitionBlocks' -and $Descriptor.Definition) { Install-ManifestedRuntime -Definition $Descriptor.Definition -Facts $facts -RefreshRequested:$CommandOptions.RefreshRequested -CommandOptions $CommandOptions -LocalRoot $CommandOptions.LocalRoot } else { & $Descriptor.InstallActionFunction -Descriptor $Descriptor -Facts $facts -CommandOptions $CommandOptions } return [pscustomobject]@{ Changed = ($rawResult -and $rawResult.PSObject.Properties['Action'] -and ($rawResult.Action -ne 'Skipped')) RestartRequired = if ($rawResult -and $rawResult.PSObject.Properties['RestartRequired']) { [bool]$rawResult.RestartRequired } else { $false } Result = $rawResult Warnings = @() Dependency = $null } } function Invoke-ManifestedDescriptorPostInstallStep { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Descriptor, [Parameter(Mandatory = $true)] [hashtable]$CommandOptions ) $facts = Get-ManifestedRuntimeFactsFromContext -Context $Descriptor -LocalRoot $CommandOptions.LocalRoot -FactsCache $(if ($CommandOptions.ContainsKey('FactsCache')) { $CommandOptions['FactsCache'] } else { @{} }) $rawResult = Invoke-ManifestedPostInstallSteps -Definition $Descriptor.Definition -Facts $facts -LocalRoot $CommandOptions.LocalRoot return [pscustomobject]@{ Changed = ($rawResult -and $rawResult.PSObject.Properties['Action'] -and ($rawResult.Action -notin @('Skipped', 'Reused'))) RestartRequired = $false Result = $rawResult Warnings = @() Dependency = $null } } function Invoke-ManifestedDescriptorEnvironmentSyncStep { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Descriptor, [Parameter(Mandatory = $true)] [hashtable]$CommandOptions ) $facts = Get-ManifestedRuntimeFactsFromContext -Context $Descriptor -LocalRoot $CommandOptions.LocalRoot -FactsCache $(if ($CommandOptions.ContainsKey('FactsCache')) { $CommandOptions['FactsCache'] } else { @{} }) $environmentResult = Get-ManifestedCommandEnvironmentResult -Descriptor $Descriptor -Facts $facts if (-not $environmentResult.Applicable -or $environmentResult.IsAligned) { return [pscustomobject]@{ Changed = $false RestartRequired = $false Result = $environmentResult Warnings = @() Dependency = $null } } $syncedResult = Sync-ManifestedCommandLineEnvironment -Descriptor $Descriptor -Facts $facts return [pscustomobject]@{ Changed = [bool]($syncedResult.ProcessPathUpdated -or $syncedResult.UserPathUpdated) RestartRequired = $false Result = $syncedResult Warnings = @() Dependency = $null } } function Invoke-ManifestedDependencyRuntimeStep { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Step ) $commandParameters = @{} if ($Step.HandlerArguments.ContainsKey('RefreshParameterName') -and -not [string]::IsNullOrWhiteSpace($Step.HandlerArguments['RefreshParameterName']) -and $Step.HandlerArguments.ContainsKey('RefreshRequested') -and $Step.HandlerArguments['RefreshRequested']) { $commandParameters[$Step.HandlerArguments['RefreshParameterName']] = $true } $dependencyResult = & $Step.HandlerArguments['DependencyCommandName'] @commandParameters $dependencyChanged = $false if ($dependencyResult -and $dependencyResult.PSObject.Properties['ExecutedSteps']) { $dependencyChanged = (@($dependencyResult.ExecutedSteps | Where-Object { $_.Changed }).Count -gt 0) } return [pscustomobject]@{ Changed = $dependencyChanged RestartRequired = if ($dependencyResult -and $dependencyResult.PSObject.Properties['RestartRequired']) { [bool]$dependencyResult.RestartRequired } else { $false } Result = $dependencyResult Warnings = @() Dependency = [pscustomobject]@{ RuntimeName = $Step.HandlerArguments['DependencyRuntimeName'] CommandName = $Step.HandlerArguments['DependencyCommandName'] Result = $dependencyResult WasExecuted = $dependencyChanged } } } function Invoke-ManifestedRuntimePlanStep { [CmdletBinding(SupportsShouldProcess = $true)] param( [Parameter(Mandatory = $true)] [pscustomobject]$Descriptor, [Parameter(Mandatory = $true)] [pscustomobject]$Step, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCmdlet]$PSCmdletObject, [Parameter(Mandatory = $true)] [hashtable]$CommandOptions ) if ($Step.IsMutation -and -not $PSCmdletObject.ShouldProcess($Step.Target, $Step.Action)) { return [pscustomobject]@{ ExecutedStep = [pscustomobject]@{ Name = $Step.Name Kind = $Step.Kind Reason = $Step.Reason Action = $Step.Action Target = $Step.Target Changed = $false RestartRequired = $false Outcome = 'Skipped' Result = $null RequiresElevation = [bool]$Step.RequiresElevation } Dependency = $null Stopped = $true } } $invokeParameters = @{ Descriptor = $Descriptor CommandOptions = $CommandOptions } foreach ($entry in $Step.HandlerArguments.GetEnumerator()) { $invokeParameters[$entry.Key] = $entry.Value } if ($CommandOptions.ContainsKey('FactsCache') -and $CommandOptions['FactsCache']) { $CommandOptions['FactsCache'].Clear() } $rawExecution = & $Step.HandlerFunction @invokeParameters return [pscustomobject]@{ ExecutedStep = [pscustomobject]@{ Name = $Step.Name Kind = $Step.Kind Reason = $Step.Reason Action = $Step.Action Target = $Step.Target Changed = [bool]$rawExecution.Changed RestartRequired = [bool]$rawExecution.RestartRequired Outcome = 'Executed' Result = $rawExecution.Result RequiresElevation = [bool]$Step.RequiresElevation } Dependency = $rawExecution.Dependency Stopped = $false } } function Invoke-ManifestedRuntimeInitialization { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$CommandName, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCmdlet]$PSCmdletObject, [bool]$RefreshRequested = $false, [hashtable]$CommandOptions = @{}, [switch]$WhatIfMode ) $descriptor = Get-ManifestedCommandContext -CommandName $CommandName if (-not $descriptor) { throw "Could not resolve a runtime descriptor for command '$CommandName'." } $requestedAtUtc = (Get-Date).ToUniversalTime().ToString('o') $localRoot = (Get-ManifestedLayout).LocalRoot $commandOptions = @{} foreach ($entry in $CommandOptions.GetEnumerator()) { $commandOptions[$entry.Key] = $entry.Value } $commandOptions['LocalRoot'] = $localRoot $commandOptions['RefreshRequested'] = [bool]$RefreshRequested $commandOptions['FactsCache'] = @{} $factsBefore = Get-ManifestedRuntimeFactsFromContext -Context $descriptor -LocalRoot $localRoot -FactsCache $commandOptions['FactsCache'] $plan = @(Get-ManifestedCommandPlanFromContext -Context $descriptor -Facts $factsBefore -RefreshRequested:$RefreshRequested) $elevationPlan = Get-ManifestedCommandElevationPlan -CommandName $descriptor.CommandName -PlanSteps $plan -LocalRoot $localRoot -WhatIfMode:$WhatIfMode if ($WhatIfMode) { $factsAfter = Get-ManifestedRuntimeFactsFromContext -Context $descriptor -LocalRoot $localRoot -FactsCache @{} $environmentResult = $null if ($descriptor.PSObject.Properties['SupportsEnvironmentSync'] -and $descriptor.SupportsEnvironmentSync) { $environmentResult = Get-ManifestedCommandEnvironmentResult -Descriptor $descriptor -Facts $factsAfter } return [pscustomobject]@{ CommandName = $descriptor.CommandName RuntimeName = $descriptor.RuntimeName FactsBefore = $factsBefore Dependencies = @() Plan = @($plan | ForEach-Object { Convert-ManifestedPlanStepForOutput -Step $_ }) ExecutedSteps = @() FactsAfter = $factsAfter EnvironmentResult = $environmentResult RestartRequired = $false Warnings = @() Errors = @() Elevation = $elevationPlan } } $elevatedCommandParameters = @{} if ($descriptor.PSObject.Properties['Definition'] -and $descriptor.Definition) { $refreshSwitchName = if ($descriptor.Definition.PSObject.Properties.Match('refreshSwitchName').Count -gt 0) { $descriptor.Definition.refreshSwitchName } else { $null } if (-not [string]::IsNullOrWhiteSpace($refreshSwitchName) -and $RefreshRequested) { $elevatedCommandParameters[$refreshSwitchName] = $true } } foreach ($entry in $CommandOptions.GetEnumerator()) { if ($entry.Key -in @('LocalRoot', 'RefreshRequested')) { continue } if ($null -ne $entry.Value) { $elevatedCommandParameters[$entry.Key] = $entry.Value } } $elevatedResult = Invoke-ManifestedElevatedCommand -ElevationPlan $elevationPlan -CommandName $descriptor.CommandName -CommandParameters $elevatedCommandParameters if ($null -ne $elevatedResult) { return $elevatedResult } $executedSteps = New-Object System.Collections.Generic.List[object] $dependencyReports = New-Object System.Collections.Generic.List[object] $restartRequired = $false foreach ($step in @($plan)) { $execution = Invoke-ManifestedRuntimePlanStep -Descriptor $descriptor -Step $step -PSCmdletObject $PSCmdletObject -CommandOptions $commandOptions $executedSteps.Add($execution.ExecutedStep) | Out-Null if ($execution.Dependency) { $dependencyReports.Add($execution.Dependency) | Out-Null } if ($execution.ExecutedStep.RestartRequired) { $restartRequired = $true } if ($execution.Stopped) { break } } $factsAfter = Get-ManifestedRuntimeFactsFromContext -Context $descriptor -LocalRoot $localRoot -FactsCache @{} $environmentResult = $null if ($descriptor.PSObject.Properties['SupportsEnvironmentSync'] -and $descriptor.SupportsEnvironmentSync) { $environmentResult = Get-ManifestedCommandEnvironmentResult -Descriptor $descriptor -Facts $factsAfter } $result = [pscustomobject]@{ CommandName = $descriptor.CommandName RuntimeName = $descriptor.RuntimeName FactsBefore = $factsBefore Dependencies = @($dependencyReports) Plan = @($plan | ForEach-Object { Convert-ManifestedPlanStepForOutput -Step $_ }) ExecutedSteps = @($executedSteps) FactsAfter = $factsAfter EnvironmentResult = $environmentResult RestartRequired = [bool]$restartRequired Warnings = @() Errors = @() Elevation = $elevationPlan } Save-ManifestedCommandReport -CommandName $descriptor.CommandName -RuntimeName $descriptor.RuntimeName -Result $result -InvocationInput @{ RefreshRequested = [bool]$RefreshRequested WhatIfMode = [bool]$WhatIfMode Options = [pscustomobject]$elevatedCommandParameters } -RequestedAtUtc $requestedAtUtc -CompletedAtUtc ((Get-Date).ToUniversalTime().ToString('o')) -LocalRoot $localRoot | Out-Null return $result } function Invoke-ManifestedCommandInitialization { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCmdlet]$PSCmdletObject, [bool]$RefreshRequested = $false, [hashtable]$CommandOptions = @{}, [switch]$WhatIfMode ) $definition = Get-ManifestedCommandDefinition -Name $Name if (-not $definition) { throw "Could not resolve a packaged command definition for '$Name'." } return (Invoke-ManifestedRuntimeInitialization -CommandName $definition.commandName -PSCmdletObject $PSCmdletObject -RefreshRequested:$RefreshRequested -CommandOptions $CommandOptions -WhatIfMode:$WhatIfMode) } |