Public/Invoke-EFManagementAgentAction.ps1
|
function Invoke-EFManagementAgentAction { <# .SYNOPSIS Previews or requests one guarded Intune or Configuration Manager support action. .DESCRIPTION Offers a fixed allowlist of local management-agent actions. Intune and Configuration Manager can start or restart their agent service. Configuration Manager can also request machine policy or evaluate machine policy that is already local. Every action can contact the configured management service and can lead to assigned applications, scripts, policy, updates, or other work. Use WhatIf first. Actual actions require Administrator permission, AllowManagementTraffic, and normal PowerShell confirmation. This command does not prove that asynchronous check-in or policy work finished successfully. EndpointForge does not expose arbitrary commands, services, CIM methods, schedule IDs, remote computers, cache deletion, re-enrollment, reinstall, or policy reset through this command. .PARAMETER Agent The one local agent to use. ConfigurationManager is also commonly called ConfigMgr, SCCM, or CCM; those familiar names are accepted. .PARAMETER Action StartAgentService or RestartAgentService can be used with either agent. RequestMachinePolicy and EvaluateMachinePolicy can be used only with ConfigurationManager. .PARAMETER AllowManagementTraffic Confirms that the action is allowed to contact this computer's configured management service and may begin assigned management work. It does not bypass WhatIf, confirmation, Administrator permission, or the fixed action allowlist. .PARAMETER TimeoutSeconds Maximum time to wait for the local service transition or Configuration Manager client request. A timeout after a request begins can leave the result uncertain. .EXAMPLE Invoke-EFManagementAgentAction -Agent Intune -Action RestartAgentService -WhatIf .EXAMPLE Invoke-EFManagementAgentAction -Agent ConfigurationManager -Action RequestMachinePolicy -AllowManagementTraffic -Confirm:$false .OUTPUTS EndpointForge.ManagementAgentActionResult .LINK Get-EFManagementAgentHealth #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] [OutputType('EndpointForge.ManagementAgentActionResult')] param( [Parameter(Mandatory)] [ValidateSet('Intune', 'ConfigurationManager', 'CCM', 'SCCM', 'ConfigMgr')] [string]$Agent, [Parameter(Mandatory)] [ValidateSet('StartAgentService', 'RestartAgentService', 'RequestMachinePolicy', 'EvaluateMachinePolicy')] [string]$Action, [switch]$AllowManagementTraffic, [ValidateRange(5, 300)] [int]$TimeoutSeconds = 60 ) $null = Test-EFWindows -Throw $canonicalAgent = if ($Agent -eq 'Intune') { 'Intune' } else { 'ConfigurationManager' } $definition = Get-EFManagementAgentDefinition -Agent $canonicalAgent if ($Action -notin @($definition.AvailableActions)) { throw [System.ArgumentException]::new( "Action '$Action' is not available for $canonicalAgent. Available actions: $($definition.AvailableActions -join ', ')." ) } $correlationId = [guid]::NewGuid().ToString() $startedAtUtc = [DateTime]::UtcNow $before = Get-EFManagementAgentHealth -Agent $canonicalAgent -TimeoutSeconds ([math]::Min(30, $TimeoutSeconds)) $computerName = [string]$before.ComputerName $target = "$computerName/$canonicalAgent" $actionDescription = switch ($Action) { 'StartAgentService' { 'Start the local management agent service; management traffic and assigned work may begin' } 'RestartAgentService' { 'Restart the local management agent service; active work may be interrupted and a management check-in may begin' } 'RequestMachinePolicy' { 'Ask the local Configuration Manager client to contact its configured service for machine policy' } 'EvaluateMachinePolicy' { 'Ask the local Configuration Manager client to evaluate already-downloaded machine policy' } } if (-not $PSCmdlet.ShouldProcess($target, $actionDescription)) { $outcome = if ($WhatIfPreference) { 'WhatIf' } else { 'Skipped' } $summary = if ($WhatIfPreference) { "Preview only: EndpointForge would request $Action for $canonicalAgent. Windows was not changed and no management traffic was initiated." } else { 'The action was not approved. Windows was not changed and no management traffic was initiated.' } return [pscustomobject][ordered]@{ PSTypeName = 'EndpointForge.ManagementAgentActionResult' ReceiptVersion = '1.0' CorrelationId = $correlationId ComputerName = $computerName Agent = $canonicalAgent Action = $Action StartedAtUtc = $startedAtUtc CompletedAtUtc = [DateTime]::UtcNow Outcome = $outcome IsSuccessful = $outcome -eq 'WhatIf' ChangeMayHaveOccurred = $false RequestAccepted = $false ImmediateEffectVerified = $false BeforeStatus = [string]$before.LocalStatus AfterStatus = [string]$before.LocalStatus BeforeServiceStatus = [string]$before.ServiceStatus AfterServiceStatus = [string]$before.ServiceStatus NetworkActivityExpected = $true NetworkActivityAllowed = [bool]$AllowManagementTraffic RebootRequired = $false CanAutomaticallyRollback = $false Summary = $summary NextStep = if ($outcome -eq 'WhatIf') { 'Review the preview. An administrator can approve the same fixed action after management traffic is authorized.' } else { 'No action is required unless you choose to request it again.' } RecoveryGuidance = 'No change was made.' SafetyNotes = 'Starting or restarting a management agent can contact its configured service and begin assigned work. A restart can interrupt work already in progress.' } } if (-not $AllowManagementTraffic) { throw [System.InvalidOperationException]::new( 'This action can contact the configured management service and begin assigned work. Review the action, then add -AllowManagementTraffic when that activity is approved.' ) } if (-not (Test-EFAdministrator)) { throw [System.UnauthorizedAccessException]::new( 'Requesting a management-agent action requires PowerShell opened with Run as Administrator. Use -WhatIf for a no-change preview.' ) } Write-EFLog -Message "Management agent action started for $canonicalAgent." -CorrelationId $correlationId ` -Data @{ agent = $canonicalAgent; action = $Action; managementTrafficAllowed = $true } try { $operation = Invoke-EFManagementAgentOperation -Agent $canonicalAgent -Action $Action -TimeoutSeconds $TimeoutSeconds } catch { $operation = [pscustomobject]@{ Outcome = 'Failed' IsSuccessful = $false ChangeMayHaveOccurred = $true RequestAccepted = $false ImmediateEffectVerified = $false BeforeServiceStatus = [string]$before.ServiceStatus AfterServiceStatus = $null Message = 'The management-agent action ended without a trustworthy result. EndpointForge does not assume it completed.' NextStep = 'Check the current local agent state and approved agent logs before trying another action.' RecoveryGuidance = 'The action may have begun before the result became unavailable. EndpointForge cannot automatically undo management work that may already have started.' } } $requiredOperationProperties = @( 'Outcome', 'IsSuccessful', 'ChangeMayHaveOccurred', 'RequestAccepted', 'ImmediateEffectVerified', 'BeforeServiceStatus', 'AfterServiceStatus', 'Message', 'NextStep', 'RecoveryGuidance' ) $operationResultIsComplete = $true foreach ($requiredOperationProperty in $requiredOperationProperties) { if (-not (Test-EFPropertyPresent -InputObject $operation -Name $requiredOperationProperty)) { $operationResultIsComplete = $false break } } if (-not $operationResultIsComplete) { $operation = [pscustomobject]@{ Outcome = 'Failed' IsSuccessful = $false ChangeMayHaveOccurred = $true RequestAccepted = $false ImmediateEffectVerified = $false BeforeServiceStatus = [string]$before.ServiceStatus AfterServiceStatus = $null Message = 'The management-agent action returned an incomplete result. EndpointForge does not assume it completed.' NextStep = 'Check the current local agent state and approved agent logs before trying another action.' RecoveryGuidance = 'The action may have begun before the result became unavailable. EndpointForge cannot automatically undo management work that may already have started.' } } $after = try { Get-EFManagementAgentHealth -Agent $canonicalAgent -TimeoutSeconds ([math]::Min(30, $TimeoutSeconds)) } catch { $null } $afterStatus = if ($null -ne $after) { [string]$after.LocalStatus } else { 'CouldNotCheck' } $afterServiceStatus = [string](Get-EFPropertyValue -InputObject $operation -Name 'AfterServiceStatus' -Default '') if ([string]::IsNullOrWhiteSpace($afterServiceStatus) -and $null -ne $after) { $afterServiceStatus = [string]$after.ServiceStatus } $result = [pscustomobject][ordered]@{ PSTypeName = 'EndpointForge.ManagementAgentActionResult' ReceiptVersion = '1.0' CorrelationId = $correlationId ComputerName = $computerName Agent = $canonicalAgent Action = $Action StartedAtUtc = $startedAtUtc CompletedAtUtc = [DateTime]::UtcNow Outcome = [string]$operation.Outcome IsSuccessful = [bool]$operation.IsSuccessful ChangeMayHaveOccurred = [bool]$operation.ChangeMayHaveOccurred RequestAccepted = [bool]$operation.RequestAccepted ImmediateEffectVerified = [bool]$operation.ImmediateEffectVerified BeforeStatus = [string]$before.LocalStatus AfterStatus = $afterStatus BeforeServiceStatus = if ([string]::IsNullOrWhiteSpace([string]$operation.BeforeServiceStatus)) { [string]$before.ServiceStatus } else { [string]$operation.BeforeServiceStatus } AfterServiceStatus = $afterServiceStatus NetworkActivityExpected = $true NetworkActivityAllowed = $true RebootRequired = $false CanAutomaticallyRollback = $false Summary = [string]$operation.Message NextStep = [string]$operation.NextStep RecoveryGuidance = [string]$operation.RecoveryGuidance SafetyNotes = 'Starting or restarting a management agent can contact its configured service and begin assigned work. A restart can interrupt work already in progress.' } Write-EFLog -Message "Management agent action finished for $canonicalAgent." ` -Level $(if ($result.IsSuccessful) { 'Information' } else { 'Warning' }) -CorrelationId $correlationId ` -Data @{ agent = $canonicalAgent; action = $Action; outcome = $result.Outcome; changeMayHaveOccurred = $result.ChangeMayHaveOccurred } return $result } |