Private/WinGet/Sync-IntuneWinGetProactiveRemediation.ps1
|
function Sync-IntuneWinGetProactiveRemediation { [CmdletBinding()] [OutputType([PSCustomObject[]])] param( [Parameter(Mandatory)] [psobject[]]$Templates, [Parameter()] [switch]$RemoveExisting, [Parameter()] [bool]$WhatIfEnabled = $false ) function Get-ExistingRemediation { param( [Parameter(Mandatory)] [string]$DisplayName ) $escapedDisplayName = $DisplayName.Replace("'", "''") $filter = [uri]::EscapeDataString("displayName eq '$escapedDisplayName'") $response = Invoke-HydrationGraphRequest -Method GET -Uri "beta/deviceManagement/deviceHealthScripts?`$filter=$filter" return @($response.value) } function Test-OwnedWinGetRemediation { param( [Parameter(Mandatory)] [psobject]$ExistingRemediation, [Parameter(Mandatory)] [string]$Scope ) return (Test-HydrationKitObject -Description ([string]$ExistingRemediation.description)) -and ([string]$ExistingRemediation.description -like '*Imported from WinGet*') -and ([string]$ExistingRemediation.description -like "*WinGetRemediationScope: $Scope*") } function Remove-OwnedWinGetRemediation { param( [Parameter(Mandatory)] [psobject]$Definition, [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]]$OwnedExisting ) if ($OwnedExisting.Count -eq 0) { return $false } if ($WhatIfEnabled) { foreach ($existingRemediation in $OwnedExisting) { $results.Add((Add-HydrationDryRunResult -Action 'WouldDelete' -Name $Definition.DisplayName -Id $existingRemediation.id -Type 'WinGetRemediation')) } return $true } foreach ($existingRemediation in $OwnedExisting) { try { Invoke-HydrationGraphRequest -Method DELETE -Uri "beta/deviceManagement/deviceHealthScripts/$($existingRemediation.id)" | Out-Null Write-HydrationLog -Message " Deleted: $($Definition.DisplayName)" -Level Info $results.Add((New-HydrationResult -Name $Definition.DisplayName -Id $existingRemediation.id -Type 'WinGetRemediation' -Action 'Deleted' -Status 'Removed')) } catch { $errorMessage = Get-GraphErrorMessage -ErrorRecord $_ Write-HydrationLog -Message " Failed: $($Definition.DisplayName) - $errorMessage" -Level Warning $results.Add((New-HydrationResult -Name $Definition.DisplayName -Id $existingRemediation.id -Type 'WinGetRemediation' -Action 'Failed' -Status $errorMessage)) } } return $true } $results = [System.Collections.Generic.List[object]]::new() $definitions = @( Get-WinGetRemediationDefinition -Scope 'system' -TemplateSet $Templates Get-WinGetRemediationDefinition -Scope 'user' -TemplateSet $Templates ) $availability = Get-IntuneProactiveRemediationAvailability if (-not $availability.IsAvailable) { Write-HydrationLog -Message " Skipped: WinGet proactive remediations - $($availability.Message)" -Level Warning return @( New-HydrationResult -Name 'WinGet proactive remediations' -Type 'WinGetRemediation' -Action 'Skipped' -Status $availability.Status ) } foreach ($definition in $definitions) { if ($definition.PackageIdentifiers.Count -eq 0 -and -not $RemoveExisting) { $existingRemediations = Get-ExistingRemediation -DisplayName $definition.DisplayName $ownedExisting = @($existingRemediations | Where-Object { Test-OwnedWinGetRemediation -ExistingRemediation $_ -Scope $definition.Scope }) if (Remove-OwnedWinGetRemediation -Definition $definition -OwnedExisting $ownedExisting) { continue } Write-HydrationLog -Message " Skipped: $($definition.DisplayName) - no packages for scope." -Level Info $results.Add((New-HydrationResult -Name $definition.DisplayName -Type 'WinGetRemediation' -Action 'Skipped' -Status 'No packages')) continue } $existingRemediations = Get-ExistingRemediation -DisplayName $definition.DisplayName $ownedExisting = @($existingRemediations | Where-Object { Test-OwnedWinGetRemediation -ExistingRemediation $_ -Scope $definition.Scope }) if ($RemoveExisting) { $null = Remove-OwnedWinGetRemediation -Definition $definition -OwnedExisting $ownedExisting continue } $ownedExistingRemediation = $ownedExisting | Select-Object -First 1 if ($existingRemediations.Count -gt 0 -and -not $ownedExistingRemediation) { Write-HydrationLog -Message " Failed: $($definition.DisplayName) - A remediation with this name already exists but is not owned by Intune Hydration Kit." -Level Warning $results.Add((New-HydrationResult -Name $definition.DisplayName -Type 'WinGetRemediation' -Action 'Failed' -Status 'Name collision')) continue } $fingerprint = Get-WinGetRemediationFingerprint -PackageIdentifiers $definition.PackageIdentifiers if ($ownedExistingRemediation -and [string]$ownedExistingRemediation.description -like "*WinGetPackageFingerprint: $fingerprint*") { Write-HydrationLog -Message " Skipped: $($definition.DisplayName)" -Level Info $results.Add((New-HydrationResult -Name $definition.DisplayName -Id $ownedExistingRemediation.id -Type 'WinGetRemediation' -Action 'Skipped' -Status 'Already current')) continue } if ($WhatIfEnabled) { $action = if ($ownedExistingRemediation) { 'WouldUpdate' } else { 'WouldCreate' } $results.Add((Add-HydrationDryRunResult -Action $action -Name $definition.DisplayName -Id $ownedExistingRemediation.id -Type 'WinGetRemediation')) continue } $body = New-WinGetRemediationBody -Definition $definition -IncludeCreateOnlyProperties (-not $ownedExistingRemediation) if ($ownedExistingRemediation) { Invoke-HydrationGraphRequest -Method PATCH -Uri "beta/deviceManagement/deviceHealthScripts/$($ownedExistingRemediation.id)" -Body $body | Out-Null Write-HydrationLog -Message " Updated: $($definition.DisplayName)" -Level Info $results.Add((New-HydrationResult -Name $definition.DisplayName -Id $ownedExistingRemediation.id -Type 'WinGetRemediation' -Action 'Updated' -Status "Packages=$($definition.PackageIdentifiers.Count)")) } else { $createdRemediation = Invoke-HydrationGraphRequest -Method POST -Uri 'beta/deviceManagement/deviceHealthScripts' -Body $body Write-HydrationLog -Message " Created: $($definition.DisplayName)" -Level Info $results.Add((New-HydrationResult -Name $definition.DisplayName -Id $createdRemediation.id -Type 'WinGetRemediation' -Action 'Created' -Status "Packages=$($definition.PackageIdentifiers.Count)")) } } return @($results) } |