Public/Invoke-IntuneRemediation.ps1
|
function Invoke-IntuneRemediation { <# .SYNOPSIS Trigger Intune Proactive Remediation scripts on-demand for single or multiple devices. .DESCRIPTION Connects to Microsoft Graph, lists your remediation scripts, and lets you trigger the selected one on target devices. Supports single device mode or multi-device mode with a WPF GUI featuring pagination. .PARAMETER DeviceName The name of a specific device to run remediation on. When specified, runs in single device mode. .PARAMETER MultiDevice Switch to enable multi-device mode with a WPF GUI for selecting multiple devices. .PARAMETER ClientId Client ID of the app registration to use for authentication. If not provided, checks IROD_CLIENTID environment variable. .PARAMETER TenantId Tenant ID to use with the specified app registration. If not provided, checks IROD_TENANTID environment variable. .EXAMPLE Invoke-IntuneRemediation Runs in interactive mode, prompting you to choose between single device or multi-device mode. .EXAMPLE Invoke-IntuneRemediation -DeviceName "DESKTOP-ABC123" Runs remediation on a single device. .EXAMPLE Invoke-IntuneRemediation -MultiDevice Opens WPF GUI to select multiple devices for remediation. .NOTES Requires Microsoft.Graph.Authentication module (will be installed automatically if missing). Requires appropriate Microsoft Graph permissions. #> [CmdletBinding()] param( [string]$DeviceName, [switch]$MultiDevice, [string]$ClientId, [string]$TenantId, [switch]$Help ) # Display help if requested if ($Help) { Get-Help Invoke-IntuneRemediation -Detailed return } # Check for module updates Test-IRODUpdate # Check for environment variables if parameters not provided if ([string]::IsNullOrWhiteSpace($ClientId)) { $ClientId = $env:IROD_CLIENTID } if ([string]::IsNullOrWhiteSpace($TenantId)) { $TenantId = $env:IROD_TENANTID } Clear-Host Write-Host "" Write-Host "[ I R O D ]" -ForegroundColor Cyan Write-Host "" # Determine execution mode FIRST $executionMode = $null if ($MultiDevice) { $executionMode = 'MultiDevice' Write-Host "[Mode] Multi-Device (from parameter)" -ForegroundColor Gray } elseif ($DeviceName) { $executionMode = 'SingleDevice' Write-Host "[Mode] Single Device: $DeviceName (from parameter)" -ForegroundColor Gray } else { # Prompt user to choose mode Write-Host " [1] Single Device" -ForegroundColor Green Write-Host " Run remediation on one specific device" -ForegroundColor Magenta Write-Host "" Write-Host " [2] Multi-Device" -ForegroundColor Green Write-Host " Select multiple devices via GUI" -ForegroundColor Magenta Write-Host "" Write-Host " [Q] Quit" -ForegroundColor Red Write-Host "" do { $choice = Read-Host "Enter choice (1, 2, or Q)" if ($choice -eq 'Q' -or $choice -eq 'q') { # Check if there's an active Graph session and disconnect try { $context = Get-MgContext -ErrorAction SilentlyContinue if ($context) { Write-Host "`nDisconnecting from Microsoft Graph..." -ForegroundColor Red Disconnect-MgGraph | Out-Null Write-Host "Disconnected." -ForegroundColor Green } } catch { # Silently continue if there's an issue checking/disconnecting } Write-Host "Exiting." -ForegroundColor Gray return } } while ($choice -ne '1' -and $choice -ne '2') if ($choice -eq '1') { $executionMode = 'SingleDevice' Clear-Host Write-Host "" Write-Host "[ I R O D ]" -ForegroundColor Cyan Write-Host "" $DeviceName = Read-Host "Enter device name" if ([string]::IsNullOrWhiteSpace($DeviceName)) { Write-Host "`nError: No device name provided." -ForegroundColor Red Write-Host "Exiting." -ForegroundColor Gray return } Write-Host "Target device: $DeviceName" -ForegroundColor Green } else { $executionMode = 'MultiDevice' Clear-Host Write-Host "" Write-Host "[ I R O D ]" -ForegroundColor Cyan Write-Host "" } } # Connect if (-not (Connect-ToGraph -ClientId $ClientId -TenantId $TenantId)) { Write-Host "`nAuthentication failed. Exiting." -ForegroundColor Red return } # Get and display scripts Write-Host "" Write-Host "Loading Remediation Scripts" -ForegroundColor Cyan $scripts = Get-RemediationScripts if ($scripts.Count -eq 0) { Write-Host "`nNo remediation scripts found in Intune." -ForegroundColor Yellow Write-Host "Disconnecting..." -ForegroundColor Red Disconnect-MgGraph | Out-Null return } Write-Host "Found $($scripts.Count) remediation script$(if($scripts.Count -ne 1){'s'})" -ForegroundColor Green # Select script via WPF GUI Write-Host "" Write-Host "Select Remediation Script" -ForegroundColor Cyan Write-Host "Opening script selection window..." -ForegroundColor Gray $scriptItems = $scripts | Select-Object displayName, id | Sort-Object displayName $columns = @( @{ Header = "Script Name"; Property = "displayName"; Width = 550 } @{ Header = "ID"; Property = "id"; Width = 300 } ) $selectedScript = Show-GridSelector -Items $scriptItems -Title "Select Remediation Script" -Columns $columns if ($script:exitRequested) { Write-Host "`nExit requested. Disconnecting from Microsoft Graph..." -ForegroundColor Yellow Disconnect-MgGraph | Out-Null Write-Host "Disconnected. Goodbye!" -ForegroundColor Red return } if (-not $selectedScript) { Write-Host "`nCancelled. Disconnecting from Microsoft Graph..." -ForegroundColor Red Disconnect-MgGraph | Out-Null Write-Host "Disconnected." -ForegroundColor Red return } # Handle based on mode if ($executionMode -eq 'MultiDevice') { # Multi-device mode with WPF GUI $allDevices = Get-AllManagedDevices if ($allDevices.Count -eq 0) { Write-Host "`nNo Windows devices found in Intune." -ForegroundColor Yellow Write-Host "Disconnecting..." -ForegroundColor Red Disconnect-MgGraph | Out-Null return } $selectedDevices = Show-DeviceSelectionGui -AllDevices $allDevices if ($script:exitRequested) { Write-Host "`nExit requested. Disconnecting from Microsoft Graph..." -ForegroundColor Yellow Disconnect-MgGraph | Out-Null Write-Host "Disconnected. Goodbye!" -ForegroundColor Red return } if (-not $selectedDevices -or $selectedDevices.Count -eq 0) { Write-Host "`nNo devices selected. Cancelled. Disconnecting..." -ForegroundColor Red Disconnect-MgGraph | Out-Null Write-Host "Disconnected." -ForegroundColor Red return } Clear-Host Write-Host "" Write-Host "[ I R O D ]" -ForegroundColor Cyan Write-Host "" Write-Host "" Write-Host "Devices Selected" -ForegroundColor Green Write-Host "Selected $($selectedDevices.Count) device$(if($selectedDevices.Count -ne 1){'s'}) for remediation:" -ForegroundColor White Write-Host "" foreach ($device in $selectedDevices) { Write-Host " • $($device.DeviceName)" -ForegroundColor White Write-Host " User: $($device.UserPrincipalName)" -ForegroundColor DarkGray } # Confirm Write-Host "" Write-Host "Confirm Remediation" -ForegroundColor Yellow Write-Host " Script: " -NoNewline -ForegroundColor Gray Write-Host $selectedScript.displayName -ForegroundColor White Write-Host " Devices: " -NoNewline -ForegroundColor Gray Write-Host "$($selectedDevices.Count) selected" -ForegroundColor White Write-Host "" Write-Host " This will immediately trigger the remediation script on all selected devices." -ForegroundColor Red Write-Host "" $confirm = Read-Host "Type YES to proceed" if ($confirm -ne 'YES') { Write-Host "`nCancelled. Disconnecting..." -ForegroundColor Red Disconnect-MgGraph | Out-Null return } # Show progress GUI Show-ProgressGui -Devices $selectedDevices -ScriptName $selectedScript.displayName -ScriptId $selectedScript.id Clear-Host Write-Host "" Write-Host "[ I R O D ]" -ForegroundColor Cyan Write-Host "" Write-Host "" Write-Host "Remediation Completed" -ForegroundColor Green Write-Host "All devices have been processed." -ForegroundColor White } else { # Single device mode Write-Host "" Write-Host "Looking Up Device" -ForegroundColor Cyan $device = Get-DeviceByName -Name $DeviceName if (-not $device) { Write-Host "`nError: Device '$DeviceName' not found in Intune." -ForegroundColor Red Write-Host "Disconnecting..." -ForegroundColor Red Disconnect-MgGraph | Out-Null return } Clear-Host Write-Host "" Write-Host "[ I R O D ]" -ForegroundColor Cyan Write-Host "" Write-Host "" Write-Host "Device Found" -ForegroundColor Green Write-Host "Selected device for remediation:" -ForegroundColor White Write-Host "" Write-Host " • $($device.deviceName)" -ForegroundColor White Write-Host " User: $($device.userPrincipalName)" -ForegroundColor DarkGray # Confirm Write-Host "" Write-Host "Confirm Remediation" -ForegroundColor Yellow Write-Host " Script: " -NoNewline -ForegroundColor Gray Write-Host $selectedScript.displayName -ForegroundColor White Write-Host " Device: " -NoNewline -ForegroundColor Gray Write-Host $device.deviceName -ForegroundColor White Write-Host "" Write-Host " This will immediately trigger the remediation script on this device." -ForegroundColor Red Write-Host "" $confirm = Read-Host "Type YES to proceed" if ($confirm -ne 'YES') { Write-Host "`nCancelled. Disconnecting..." -ForegroundColor Red Disconnect-MgGraph | Out-Null return } # Create device object for progress GUI $deviceForGui = [PSCustomObject]@{ Id = $device.id DeviceName = $device.deviceName } # Show progress GUI Show-ProgressGui -Devices @($deviceForGui) -ScriptName $selectedScript.displayName -ScriptId $selectedScript.id Clear-Host Write-Host "" Write-Host "[ I R O D ]" -ForegroundColor Cyan Write-Host "" Write-Host "" Write-Host "Remediation Completed" -ForegroundColor Green Write-Host "Device has been processed." -ForegroundColor White } # Prompt to run again or exit Write-Host "" Write-Host "Next Action" -ForegroundColor Cyan Write-Host "" Write-Host " [R] Run again" -ForegroundColor Green Write-Host " [X] Exit" -ForegroundColor Red Write-Host "" $runAgain = Read-Host "Choice (R/X)" if ($runAgain -eq 'R' -or $runAgain -eq 'r') { Write-Host "" Write-Host "Restarting tool..." -ForegroundColor Cyan Write-Host "" Invoke-IntuneRemediation } else { Write-Host "" Write-Host "Disconnecting from Microsoft Graph..." -ForegroundColor Red Disconnect-MgGraph | Out-Null Write-Host "Disconnected." -ForegroundColor Green Write-Host "" } } |