Views/Scripts.ps1
|
function Show-InTUIScriptsView { <# .SYNOPSIS Displays the Scripts & Remediations view with navigation to device scripts and proactive remediations. #> [CmdletBinding()] param() $exitView = $false while (-not $exitView) { Clear-Host Show-InTUIHeader Show-InTUIBreadcrumb -Path @('Home', 'Scripts & Remediations') $choices = @( 'Device Management Scripts', 'Proactive Remediations', '─────────────', 'Back to Home' ) $selection = Show-InTUIMenu -Title "[yellow]Scripts & Remediations[/]" -Choices $choices Write-InTUILog -Message "Scripts & Remediations view selection" -Context @{ Selection = $selection } switch ($selection) { 'Device Management Scripts' { Show-InTUIDeviceScriptList } 'Proactive Remediations' { Show-InTUIRemediationList } 'Back to Home' { $exitView = $true } default { continue } } } } function Show-InTUIDeviceScriptList { <# .SYNOPSIS Displays a list of device management scripts. #> [CmdletBinding()] param() $exitList = $false while (-not $exitList) { Clear-Host Show-InTUIHeader Show-InTUIBreadcrumb -Path @('Home', 'Scripts & Remediations', 'Device Management Scripts') $params = @{ Uri = '/deviceManagement/deviceManagementScripts' Beta = $true PageSize = 25 Select = 'id,displayName,description,lastModifiedDateTime,createdDateTime,fileName,runAsAccount,enforceSignatureCheck' } $scripts = Show-InTUILoading -Title "[yellow]Loading device management scripts...[/]" -ScriptBlock { Get-InTUIPagedResults @params } if ($null -eq $scripts -or $scripts.Results.Count -eq 0) { Show-InTUIWarning "No device management scripts found." Read-InTUIKey $exitList = $true continue } $scriptChoices = @() foreach ($script in $scripts.Results) { $modified = Format-InTUIDate -DateString $script.lastModifiedDateTime $runAs = if ($script.runAsAccount -eq 'system') { 'System' } else { 'User' } $displayName = "[white]$(ConvertTo-InTUISafeMarkup -Text $script.displayName)[/] [grey]| $($script.fileName) | $runAs | $modified[/]" $scriptChoices += $displayName } $choiceMap = Get-InTUIChoiceMap -Choices $scriptChoices $menuChoices = @($choiceMap.Choices + '─────────────' + 'Back') Show-InTUIStatusBar -Total $scripts.TotalCount -Showing $scripts.Results.Count $selection = Show-InTUIMenu -Title "[yellow]Select a script[/]" -Choices $menuChoices if ($selection -eq 'Back') { $exitList = $true } elseif ($selection -ne '─────────────') { $idx = $choiceMap.IndexMap[$selection] if ($null -ne $idx -and $idx -lt $scripts.Results.Count) { Show-InTUIDeviceScriptDetail -ScriptId $scripts.Results[$idx].id } } } } function Show-InTUIDeviceScriptDetail { <# .SYNOPSIS Displays detailed information about a specific device management script. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$ScriptId ) $exitDetail = $false while (-not $exitDetail) { Clear-Host Show-InTUIHeader $detailData = Show-InTUILoading -Title "[yellow]Loading script details...[/]" -ScriptBlock { $scr = Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceManagementScripts/$ScriptId" -Beta $assign = Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceManagementScripts/$ScriptId/assignments" -Beta $runStates = Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceManagementScripts/$ScriptId/deviceRunStates?`$top=200" -Beta @{ Script = $scr Assignments = $assign RunStates = $runStates } } $scriptObj = $detailData.Script $assignments = $detailData.Assignments $runStates = $detailData.RunStates if ($null -eq $scriptObj) { Show-InTUIError "Failed to load script details." Read-InTUIKey return } Show-InTUIBreadcrumb -Path @('Home', 'Scripts & Remediations', 'Device Management Scripts', $scriptObj.displayName) $runAs = if ($scriptObj.runAsAccount -eq 'system') { 'System' } else { 'User' } $propsContent = @" [bold white]$(ConvertTo-InTUISafeMarkup -Text $scriptObj.displayName)[/] [grey]Description:[/] $(if ($scriptObj.description) { $scriptObj.description.Substring(0, [Math]::Min(200, $scriptObj.description.Length)) } else { 'N/A' }) [grey]File Name:[/] $($scriptObj.fileName ?? 'N/A') [grey]Run As Account:[/] $runAs [grey]Enforce Signature Check:[/] $($scriptObj.enforceSignatureCheck ?? $false) [grey]Run As 32-Bit:[/] $($scriptObj.runAs32Bit ?? $false) [grey]Created:[/] $(Format-InTUIDate -DateString $scriptObj.createdDateTime) [grey]Last Modified:[/] $(Format-InTUIDate -DateString $scriptObj.lastModifiedDateTime) "@ Show-InTUIPanel -Title "[yellow]Script Properties[/]" -Content $propsContent -BorderColor Yellow # Assignments panel $assignmentCount = if ($assignments.value) { @($assignments.value).Count } else { 0 } $assignContent = "[grey]Total Assignments:[/] [white]$assignmentCount[/]" if ($assignments.value) { $assignContent += "`n" foreach ($assignment in $assignments.value) { $targetType = switch ($assignment.target.'@odata.type') { '#microsoft.graph.allLicensedUsersAssignmentTarget' { '[blue]All Users[/]' } '#microsoft.graph.allDevicesAssignmentTarget' { '[blue]All Devices[/]' } '#microsoft.graph.groupAssignmentTarget' { "Group: $($assignment.target.groupId)" } '#microsoft.graph.exclusionGroupAssignmentTarget' { "[red]Exclude:[/] $($assignment.target.groupId)" } default { $assignment.target.'@odata.type' -replace '#microsoft\.graph\.', '' } } $assignContent += "`n $targetType" } } Show-InTUIPanel -Title "[yellow]Assignments[/]" -Content $assignContent -BorderColor Yellow # Run state summary panel $runStateList = if ($runStates.value) { @($runStates.value) } else { @() } $succeeded = @($runStateList | Where-Object { $_.resultMessage -eq '' -or $_.errorCode -eq 0 }).Count $failed = @($runStateList | Where-Object { $_.errorCode -ne 0 -and $null -ne $_.errorCode }).Count $pending = $runStateList.Count - $succeeded - $failed $runSummaryContent = @" [grey]Total Devices:[/] [white]$($runStateList.Count)[/] [green]Succeeded:[/] $succeeded [red]Failed:[/] $failed [yellow]Pending:[/] $pending "@ Show-InTUIPanel -Title "[yellow]Run State Summary[/]" -Content $runSummaryContent -BorderColor Yellow $actionChoices = @( 'View Device Run States', 'View Script Content', '─────────────', 'Back' ) $action = Show-InTUIMenu -Title "[yellow]Script Actions[/]" -Choices $actionChoices Write-InTUILog -Message "Device script detail action" -Context @{ ScriptId = $ScriptId; ScriptName = $scriptObj.displayName; Action = $action } switch ($action) { 'View Device Run States' { Show-InTUIDeviceScriptRunStates -ScriptId $ScriptId -ScriptName $scriptObj.displayName } 'View Script Content' { Show-InTUIDeviceScriptContent -ScriptId $ScriptId -ScriptName $scriptObj.displayName } 'Back' { $exitDetail = $true } default { continue } } } } function Show-InTUIDeviceScriptRunStates { <# .SYNOPSIS Displays device run states table for a device management script. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$ScriptId, [Parameter()] [string]$ScriptName ) Clear-Host Show-InTUIHeader Show-InTUIBreadcrumb -Path @('Home', 'Scripts & Remediations', 'Device Management Scripts', $ScriptName, 'Device Run States') $runStates = Show-InTUILoading -Title "[yellow]Loading device run states...[/]" -ScriptBlock { Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceManagementScripts/$ScriptId/deviceRunStates?`$top=50&`$expand=managedDevice(`$select=deviceName)" -Beta } if (-not $runStates.value) { Show-InTUIWarning "No device run state data available for this script." Read-InTUIKey return } $rows = @() foreach ($state in $runStates.value) { $deviceName = if ($state.managedDevice -and $state.managedDevice.deviceName) { $state.managedDevice.deviceName } else { 'N/A' } $stateColor = switch ($state.resultMessage) { { $state.errorCode -eq 0 } { 'green' } { $state.errorCode -ne 0 } { 'red' } default { 'yellow' } } $statusText = if ($state.errorCode -eq 0) { 'Succeeded' } elseif ($state.errorCode) { 'Failed' } else { 'Pending' } $resultMsg = if ($state.resultMessage) { $state.resultMessage.Substring(0, [Math]::Min(80, $state.resultMessage.Length)) } else { 'N/A' } $rows += , @( $deviceName, "[$stateColor]$statusText[/]", $resultMsg, (Format-InTUIDate -DateString $state.lastStateUpdateDateTime) ) } Show-InTUITable -Title "Device Run States" -Columns @('Device', 'Status', 'Result Message', 'Last State Modified') -Rows $rows Read-InTUIKey } function Show-InTUIDeviceScriptContent { <# .SYNOPSIS Displays the decoded script content for a device management script. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$ScriptId, [Parameter()] [string]$ScriptName ) Clear-Host Show-InTUIHeader Show-InTUIBreadcrumb -Path @('Home', 'Scripts & Remediations', 'Device Management Scripts', $ScriptName, 'Script Content') $scriptObj = Show-InTUILoading -Title "[yellow]Loading script content...[/]" -ScriptBlock { Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceManagementScripts/$ScriptId" -Beta } if ($null -eq $scriptObj -or [string]::IsNullOrEmpty($scriptObj.scriptContent)) { Show-InTUIWarning "Script content not available." Read-InTUIKey return } try { $decodedContent = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($scriptObj.scriptContent)) } catch { Show-InTUIWarning "Script content not available." Read-InTUIKey return } Write-InTUILog -Message "Viewing script content" -Context @{ ScriptId = $ScriptId; ScriptName = $ScriptName } Show-InTUIPanel -Title "[yellow]Script Content - $ScriptName[/]" -Content $decodedContent -BorderColor Yellow Read-InTUIKey } function Show-InTUIRemediationList { <# .SYNOPSIS Displays a list of proactive remediation (device health) scripts. #> [CmdletBinding()] param() $exitList = $false while (-not $exitList) { Clear-Host Show-InTUIHeader Show-InTUIBreadcrumb -Path @('Home', 'Scripts & Remediations', 'Proactive Remediations') $params = @{ Uri = '/deviceManagement/deviceHealthScripts' Beta = $true PageSize = 25 Select = 'id,displayName,description,lastModifiedDateTime,createdDateTime,isGlobalScript,publisher' } $remediations = Show-InTUILoading -Title "[yellow]Loading proactive remediations...[/]" -ScriptBlock { Get-InTUIPagedResults @params } if ($null -eq $remediations -or $remediations.Results.Count -eq 0) { Show-InTUIWarning "No proactive remediations found." Read-InTUIKey $exitList = $true continue } $remediationChoices = @() foreach ($remediation in $remediations.Results) { $modified = Format-InTUIDate -DateString $remediation.lastModifiedDateTime $publisher = if ($remediation.publisher) { $remediation.publisher } else { 'N/A' } $globalScript = if ($remediation.isGlobalScript) { 'Yes' } else { 'No' } $displayName = "[white]$(ConvertTo-InTUISafeMarkup -Text $remediation.displayName)[/] [grey]| $publisher | Global: $globalScript | $modified[/]" $remediationChoices += $displayName } $choiceMap = Get-InTUIChoiceMap -Choices $remediationChoices $menuChoices = @($choiceMap.Choices + '─────────────' + 'Back') Show-InTUIStatusBar -Total $remediations.TotalCount -Showing $remediations.Results.Count $selection = Show-InTUIMenu -Title "[yellow]Select a remediation[/]" -Choices $menuChoices if ($selection -eq 'Back') { $exitList = $true } elseif ($selection -ne '─────────────') { $idx = $choiceMap.IndexMap[$selection] if ($null -ne $idx -and $idx -lt $remediations.Results.Count) { Show-InTUIRemediationDetail -ScriptId $remediations.Results[$idx].id } } } } function Show-InTUIRemediationDetail { <# .SYNOPSIS Displays detailed information about a specific proactive remediation script. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$ScriptId ) $exitDetail = $false while (-not $exitDetail) { Clear-Host Show-InTUIHeader $detailData = Show-InTUILoading -Title "[yellow]Loading remediation details...[/]" -ScriptBlock { $rem = Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceHealthScripts/$ScriptId" -Beta $assign = Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceHealthScripts/$ScriptId/assignments" -Beta $runStates = Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceHealthScripts/$ScriptId/deviceRunStates?`$top=200" -Beta @{ Remediation = $rem Assignments = $assign RunStates = $runStates } } $remediation = $detailData.Remediation $assignments = $detailData.Assignments $runStates = $detailData.RunStates if ($null -eq $remediation) { Show-InTUIError "Failed to load remediation details." Read-InTUIKey return } Show-InTUIBreadcrumb -Path @('Home', 'Scripts & Remediations', 'Proactive Remediations', $remediation.displayName) $runAs = if ($remediation.runAsAccount -eq 'system') { 'System' } else { 'User' } $propsContent = @" [bold white]$(ConvertTo-InTUISafeMarkup -Text $remediation.displayName)[/] [grey]Description:[/] $(if ($remediation.description) { $remediation.description.Substring(0, [Math]::Min(200, $remediation.description.Length)) } else { 'N/A' }) [grey]Publisher:[/] $($remediation.publisher ?? 'N/A') [grey]Global Script:[/] $($remediation.isGlobalScript ?? $false) [grey]Run As Account:[/] $runAs [grey]Run As 32-Bit:[/] $($remediation.runAs32Bit ?? $false) [grey]Created:[/] $(Format-InTUIDate -DateString $remediation.createdDateTime) [grey]Last Modified:[/] $(Format-InTUIDate -DateString $remediation.lastModifiedDateTime) "@ Show-InTUIPanel -Title "[yellow]Remediation Properties[/]" -Content $propsContent -BorderColor Yellow # Assignments panel $assignmentCount = if ($assignments.value) { @($assignments.value).Count } else { 0 } $assignContent = "[grey]Total Assignments:[/] [white]$assignmentCount[/]" if ($assignments.value) { $assignContent += "`n" foreach ($assignment in $assignments.value) { $targetType = switch ($assignment.target.'@odata.type') { '#microsoft.graph.allLicensedUsersAssignmentTarget' { '[blue]All Users[/]' } '#microsoft.graph.allDevicesAssignmentTarget' { '[blue]All Devices[/]' } '#microsoft.graph.groupAssignmentTarget' { "Group: $($assignment.target.groupId)" } '#microsoft.graph.exclusionGroupAssignmentTarget' { "[red]Exclude:[/] $($assignment.target.groupId)" } default { $assignment.target.'@odata.type' -replace '#microsoft\.graph\.', '' } } $assignContent += "`n $targetType" } } Show-InTUIPanel -Title "[yellow]Assignments[/]" -Content $assignContent -BorderColor Yellow # Run state summary panel $runStateList = if ($runStates.value) { @($runStates.value) } else { @() } $detectionSuccess = @($runStateList | Where-Object { $_.detectionState -eq 'success' }).Count $detectionFailed = @($runStateList | Where-Object { $_.detectionState -eq 'fail' }).Count $remediationSuccess = @($runStateList | Where-Object { $_.remediationState -eq 'success' }).Count $remediationFailed = @($runStateList | Where-Object { $_.remediationState -eq 'fail' }).Count $runSummaryContent = @" [grey]Total Devices:[/] [white]$($runStateList.Count)[/] [bold]Detection:[/] [green] Succeeded:[/] $detectionSuccess [red] Failed:[/] $detectionFailed [bold]Remediation:[/] [green] Succeeded:[/] $remediationSuccess [red] Failed:[/] $remediationFailed "@ Show-InTUIPanel -Title "[yellow]Run Summary[/]" -Content $runSummaryContent -BorderColor Yellow $actionChoices = @( 'View Device Run States', '─────────────', 'Back' ) $action = Show-InTUIMenu -Title "[yellow]Remediation Actions[/]" -Choices $actionChoices Write-InTUILog -Message "Remediation detail action" -Context @{ ScriptId = $ScriptId; ScriptName = $remediation.displayName; Action = $action } switch ($action) { 'View Device Run States' { Show-InTUIRemediationRunStates -ScriptId $ScriptId -ScriptName $remediation.displayName } 'Back' { $exitDetail = $true } default { continue } } } } function Show-InTUIRemediationRunStates { <# .SYNOPSIS Displays device run states table for a proactive remediation script. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$ScriptId, [Parameter()] [string]$ScriptName ) Clear-Host Show-InTUIHeader Show-InTUIBreadcrumb -Path @('Home', 'Scripts & Remediations', 'Proactive Remediations', $ScriptName, 'Device Run States') $runStates = Show-InTUILoading -Title "[yellow]Loading device run states...[/]" -ScriptBlock { Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceHealthScripts/$ScriptId/deviceRunStates?`$top=50&`$expand=managedDevice(`$select=deviceName)" -Beta } if (-not $runStates.value) { Show-InTUIWarning "No device run state data available for this remediation." Read-InTUIKey return } $rows = @() foreach ($state in $runStates.value) { $deviceName = if ($state.managedDevice -and $state.managedDevice.deviceName) { $state.managedDevice.deviceName } else { 'N/A' } $detectionColor = switch ($state.detectionState) { 'success' { 'green' } 'fail' { 'red' } default { 'yellow' } } $remediationColor = switch ($state.remediationState) { 'success' { 'green' } 'fail' { 'red' } default { 'yellow' } } $detectionText = if ($state.detectionState) { $state.detectionState } else { 'N/A' } $remediationText = if ($state.remediationState) { $state.remediationState } else { 'N/A' } $rows += , @( $deviceName, "[$detectionColor]$detectionText[/]", "[$remediationColor]$remediationText[/]", (Format-InTUIDate -DateString $state.lastSyncDateTime) ) } Show-InTUITable -Title "Device Run States" -Columns @('Device', 'Detection State', 'Remediation State', 'Last Sync') -Rows $rows Read-InTUIKey } |