Skip to content

Add proactive remediation workload - #41

Open
jorgeasaurus wants to merge 3 commits into
mainfrom
agent/proactive-remediations
Open

Add proactive remediation workload#41
jorgeasaurus wants to merge 3 commits into
mainfrom
agent/proactive-remediations

Conversation

@jorgeasaurus

Copy link
Copy Markdown
Owner

Type of Change

  • Feature and safety fix

Issue

N/A

Description

Adds six bundled, unassigned Windows Proactive Remediation templates and the Import-IntuneRemediation workload, with CLI, settings, TUI, pre-flight, scope, and orchestration integration.

The shared device-health-script synchronizer preserves exact ownership boundaries, detects assignment state before updating, and fails closed for assigned remediation packages. -WhatIf performs the same read-only assignment check, so its plan matches a live run.

Validation

  • ./build.ps1 -Task CI — passed (1,121 tests discovered; PSScriptAnalyzer: 0 errors)
  • Focused remediation Pester suite — 30 passed
  • Changed PowerShell files parse cleanly
  • git diff --check

Checklist

  • I have reviewed and tested the changes.
  • This PR is limited to the proactive remediation workload.
  • I confirm the contribution is made under the repository license.

Copilot AI review requested due to automatic review settings July 28, 2026 13:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new “Proactive Remediations” workload to IntuneHydrationKit, bundling six Windows remediation templates and integrating them into the existing settings/CLI/TUI orchestration and pre-flight access probing.

Changes:

  • Introduces Import-IntuneRemediation plus remediation template loading/fingerprinting/body/description helpers.
  • Adds a shared Sync-IntuneDeviceHealthScript synchronizer and refactors WinGet proactive remediation sync to use it.
  • Wires the new workload into orchestration, settings schema/example, scope calculation, access probes, and expands Pester coverage for the new behavior.

Reviewed changes

Copilot reviewed 43 out of 43 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
Tests/Public/Test-IntunePrerequisites.Tests.ps1 Adds coverage ensuring device health script probing is not duplicated when both WinGet apps and remediations are selected.
Tests/Public/Invoke-IntuneHydration.Tests.ps1 Verifies -Remediations switch and orchestrator calls into remediation import.
Tests/Public/Import-IntuneRemediation.Tests.ps1 New test suite for remediation create/update/delete/WhatIf and assignment-safe behavior.
Tests/Private/Sync-IntuneWinGetProactiveRemediation.Tests.ps1 Expands tests for stricter ownership requirements and ambiguous-owned matching behavior.
Tests/Private/Resolve-HydrationWorkloadPlan.Tests.ps1 Updates workload catalog expectations to include remediations.
Tests/Private/Get-HydrationRemediationTemplates.Tests.ps1 New tests validating remediation template loading, path safety, and bundled catalog parsing.
Tests/Private/Get-HydrationGraphScopes.Tests.ps1 Ensures remediation selection adds the expected Graph scopes.
Templates/Remediations/Windows/DiskPressureCleanup/Detect-DiskPressureCleanup.ps1 Adds bundled remediation detection script (disk pressure).
Templates/Remediations/Windows/DiskPressureCleanup/Remediate-DiskPressureCleanup.ps1 Adds bundled remediation script (disk pressure cleanup).
Templates/Remediations/Windows/DiskPressureCleanup/metadata.json Adds remediation template metadata (disk pressure cleanup).
Templates/Remediations/Windows/DeviceHealthReporting/Detect-DeviceHealth.ps1 Adds bundled detection-only template for device health reporting.
Templates/Remediations/Windows/DeviceHealthReporting/metadata.json Adds detection-only template metadata (device health reporting).
Templates/Remediations/Windows/AutomaticTimeZone/Detect-AutomaticTimeZone.ps1 Adds detection script for automatic time zone service state.
Templates/Remediations/Windows/AutomaticTimeZone/Remediate-AutomaticTimeZone.ps1 Adds remediation script for automatic time zone service.
Templates/Remediations/Windows/AutomaticTimeZone/metadata.json Adds remediation template metadata (automatic time zone).
Templates/Remediations/Windows/BitLockerRecoveryKeyEscrow/Detect-BitLockerRecoveryKeyEscrow.ps1 Adds detection script for BitLocker key escrow retry.
Templates/Remediations/Windows/BitLockerRecoveryKeyEscrow/Remediate-BitLockerRecoveryKeyEscrow.ps1 Adds remediation script for BitLocker key escrow retry.
Templates/Remediations/Windows/BitLockerRecoveryKeyEscrow/metadata.json Adds remediation template metadata (BitLocker escrow).
Templates/Remediations/Windows/DefenderSignatureFreshness/Detect-DefenderSignatureFreshness.ps1 Adds detection script for Defender signature age.
Templates/Remediations/Windows/DefenderSignatureFreshness/Remediate-DefenderSignatureFreshness.ps1 Adds remediation script for Defender signature refresh.
Templates/Remediations/Windows/DefenderSignatureFreshness/metadata.json Adds remediation template metadata (Defender signature freshness).
Templates/Remediations/Windows/WindowsRecoveryEnvironment/Detect-WindowsRecoveryEnvironment.ps1 Adds detection script for WinRE disabled state.
Templates/Remediations/Windows/WindowsRecoveryEnvironment/Remediate-WindowsRecoveryEnvironment.ps1 Adds remediation script to enable WinRE when safely repairable.
Templates/Remediations/Windows/WindowsRecoveryEnvironment/metadata.json Adds remediation template metadata (WinRE health).
settings.schema.json Adds imports.remediations setting.
settings.example.json Documents default remediations import selection.
Public/Orchestration/Invoke-IntuneHydration.ps1 Integrates remediation workload execution into the main orchestrator.
Public/Imports/Import-IntuneRemediation.ps1 New public entry point to import/delete bundled remediation templates.
Private/WinGet/Sync-IntuneWinGetProactiveRemediation.ps1 Refactors WinGet remediation sync to use shared device health script synchronizer.
Private/Tui/Get-HydrationTuiImportOption.ps1 Adds a TUI import option for proactive remediations.
Private/Remediations/New-HydrationRemediationDescription.ps1 Builds standardized remediation description/ownership metadata.
Private/Remediations/New-HydrationRemediationBody.ps1 Constructs the Graph body payload for device health scripts from templates.
Private/Remediations/Get-HydrationRemediationTemplates.ps1 Loads/validates remediation template metadata and resolves safe script paths.
Private/Remediations/Get-HydrationRemediationFingerprint.ps1 Generates a deterministic fingerprint for remediation template updates.
Private/DeviceHealthScripts/Sync-IntuneDeviceHealthScript.ps1 New shared synchronizer handling create/update/delete with strict ownership and assignment safety.
Private/DeviceHealthScripts/ConvertFrom-HydrationDeviceHealthScriptDescription.ps1 Parses newline-delimited metadata from device health script descriptions.
Private/Configuration/Resolve-HydrationExecutionSettings.ps1 Adds -Remediations switch integration into execution settings resolution.
Private/Configuration/Get-HydrationWorkloadCatalog.ps1 Adds remediation workload catalog entry (platform-scoped to Windows).
Private/Auth/Get-HydrationGraphWorkloadAccessProbe.ps1 Consolidates device health script access probing when either remediation workload is enabled.
Private/Auth/Get-HydrationGraphScopes.ps1 Adds remediation-required scopes to scope resolution.
Invoke-IntuneHydration.ps1 Exposes -Remediations switch in the wrapper script help/params.
IntuneHydrationKit.psm1 Exports the new public function in module loader list.
IntuneHydrationKit.psd1 Exports the new public function in module manifest.

Comment thread Templates/Remediations/Windows/AutomaticTimeZone/Remediate-AutomaticTimeZone.ps1 Outdated
Copilot AI review requested due to automatic review settings July 28, 2026 13:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 43 out of 43 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

Templates/Remediations/Windows/AutomaticTimeZone/Remediate-AutomaticTimeZone.ps1:5

  • The remediation can fail silently: Get-CimInstance -ErrorAction Stop can throw (unhandled), and Start-Service -ErrorAction SilentlyContinue suppresses failures while the script still exits 0. That can report success even when the service is still disabled/not running. Catch CIM/service-start failures and return a non-zero exit code when remediation doesn't actually succeed.
$service = Get-CimInstance -ClassName Win32_Service -Filter "Name='tzautoupdate'" -ErrorAction Stop
if ($service.StartMode -eq 'Disabled') {
    $process = Start-Process -FilePath "$env:SystemRoot\System32\sc.exe" -ArgumentList 'config', 'tzautoupdate', 'start=', 'demand' -Wait -PassThru -NoNewWindow
    if ($process.ExitCode -ne 0) {
        Write-Error "Failed to enable the automatic time zone service. ExitCode=$($process.ExitCode)"

Templates/Remediations/Windows/AutomaticTimeZone/Detect-AutomaticTimeZone.ps1:8

  • Get-CimInstance -ErrorAction Stop can throw, and Win32_Service queries can also return $null (service missing/unavailable). As written, the script can terminate with an unhandled error and Intune will treat the run as a script failure rather than a clean skip/compliance result. Consider catching CIM failures and handling missing service as a safe skip (exit 0).
$service = Get-CimInstance -ClassName Win32_Service -Filter "Name='tzautoupdate'" -ErrorAction Stop
if ($service.StartMode -eq 'Disabled') {
    Write-Output 'Automatic time zone service is disabled.'
    exit 1
}

Templates/Remediations/Windows/DiskPressureCleanup/Detect-DiskPressureCleanup.ps1:19

  • Get-CimInstance can fail or return $null (WMI/CIM issues, unexpected SystemDrive), and the script then dereferences $systemDrive.FreeSpace, which will terminate the detection script with an unhandled error. Since detection scripts should reliably return 0/1, handle CIM errors/null results as a safe skip (exit 0) instead of crashing.
$systemDrive = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DeviceID='$($env:SystemDrive)'"
$eligiblePaths = @($env:TEMP, (Join-Path -Path $env:WINDIR -ChildPath 'Temp')) | Select-Object -Unique
$eligibleSize = 0L

foreach ($path in $eligiblePaths) {

Templates/Remediations/Windows/DiskPressureCleanup/Remediate-DiskPressureCleanup.ps1:37

  • The remediation script dereferences $systemDrive.FreeSpace without validating that the CIM query succeeded. If Get-CimInstance fails/returns $null, the script will terminate with an unhandled error and remediation will be reported as failed. Handle CIM failures/null results and return a clear error/skip instead of crashing.
$systemDrive = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DeviceID='$($env:SystemDrive)'"
$freeSpaceGB = [math]::Round($systemDrive.FreeSpace / 1GB, 2)
$removedMB = [math]::Round($removedBytes / 1MB, 2)
Write-Output "Disk cleanup completed: RemovedMB=$removedMB; FreeSpaceGB=$freeSpaceGB; TargetFreeSpaceGB=$minimumFreeSpaceGB"

Copilot AI review requested due to automatic review settings July 28, 2026 13:44

Copy link
Copy Markdown
Owner Author

@copilot review the current head 22c76cbd254b0f9100e75e092c6ebfeaa7037fcb.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 43 out of 43 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

Private/Remediations/New-HydrationRemediationDescription.ps1:19

  • The description hard-codes Assignments: none, but assignment state can change after import. That line will become stale/misleading and also gets parsed as metadata by ConvertFrom-HydrationDeviceHealthScriptDescription. Consider omitting assignment state from the persisted description and relying on the runtime /assignments check instead.
        'Imported from Proactive Remediation Pack'
        "RemediationTemplateId: $($Template.TemplateId)"
        "RemediationFingerprint: $Fingerprint"
        'Assignments: none'
    ) -join "`n"

Copilot AI commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

@copilot review the current head 22c76cbd254b0f9100e75e092c6ebfeaa7037fcb.

Reviewed 22c76cb. No new issues found.

What I checked:

  • Remediate-AutomaticTimeZone.ps1Start-Service correctly uses -ErrorAction Stop inside a try/catch that writes an error and exits 1 on failure; the corresponding test asserts both the -ErrorAction Stop pattern and the failure message.
  • Sync-IntuneDeviceHealthScript.ps1 — ownership boundary detection, assignment-state check before update, and WhatIf propagation all look correct. The assignment check runs in WhatIf mode too, consistent with the PR description.
  • Import-IntuneRemediation.ps1 / private helpers — template loading, fingerprinting, body construction, and description parsing are well-structured and follow existing module conventions.
  • All 6 bundled remediation templates have valid metadata and point to existing script files.
  • Focused Pester suite: 8 passed, 0 failed.
  • CI on agent/proactive-remediations: passing.

No changes required.

@jorgeasaurus
jorgeasaurus marked this pull request as ready for review July 28, 2026 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants