Public/Remove-WingetIntuneApps.ps1
|
function Remove-WingetIntuneApps { <# .SYNOPSIS Removes Intune apps deployed via WingetIntunePublisher along with their assignment groups and remediations. .DESCRIPTION This function identifies and removes Win32 apps in Microsoft Intune that were deployed using WingetIntunePublisher (identified by their description). It also removes associated Azure AD groups and Proactive Remediations. .PARAMETER AppName Optional filter for app display name (supports wildcards). If not specified, processes all WingetIntunePublisher apps. .PARAMETER WhatIf Shows what would be deleted without actually performing the deletion. .PARAMETER Confirm Prompts for confirmation before deleting each app. .EXAMPLE Remove-WingetIntuneApps Removes all apps deployed via WingetIntunePublisher (prompts for confirmation). .EXAMPLE Remove-WingetIntuneApps -AppName "Google Chrome" Removes only Google Chrome if it was deployed via WingetIntunePublisher. .EXAMPLE Remove-WingetIntuneApps -AppName "*Adobe*" -WhatIf Shows what Adobe apps would be removed without actually deleting them. .EXAMPLE Remove-WingetIntuneApps -Confirm:$false Removes all WingetIntunePublisher apps without confirmation prompts. .NOTES Requires: Microsoft.Graph.Authentication module Permissions: DeviceManagementApps.ReadWrite.All, Group.ReadWrite.All, DeviceManagementConfiguration.ReadWrite.All #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( [Parameter(Mandatory = $false)] [string]$AppName = "*" ) Write-Host "`n=== WingetIntunePublisher App Removal ===" -ForegroundColor Cyan Write-Host "This will remove apps and their associated groups and remediations.`n" -ForegroundColor Yellow # Define the identifier for WingetIntunePublisher apps $wingetPublisherTag = $script:PublisherTag # Fetch all Win32 apps Write-Host "Fetching Win32 apps from Intune..." -ForegroundColor Cyan try { $uri = "beta/deviceAppManagement/mobileApps?`$filter=isof('microsoft.graph.win32LobApp')" $allApps = (Invoke-MgGraphRequest -Uri $uri -Method GET).value Write-Host "Found $($allApps.Count) Win32 apps in Intune" -ForegroundColor Gray } catch { Write-Error "Failed to fetch apps: $_" return } # Filter for WingetIntunePublisher apps $wingetApps = $allApps | Where-Object { $_.description -and $_.description -match [regex]::Escape($wingetPublisherTag) } if (-not $wingetApps) { Write-Host "`nNo apps found that were deployed via WingetIntunePublisher." -ForegroundColor Yellow return } # Further filter by app name if specified if ($AppName -ne "*") { $wingetApps = $wingetApps | Where-Object { $_.displayName -like $AppName } } if (-not $wingetApps) { Write-Host "`nNo apps found matching: $AppName" -ForegroundColor Yellow return } Write-Host "`nFound $($wingetApps.Count) WingetIntunePublisher apps to process:" -ForegroundColor Yellow $wingetApps | ForEach-Object { Write-Host " - $($_.displayName)" -ForegroundColor Gray } $deletedApps = 0 $deletedGroups = 0 $deletedRemediations = 0 $failedItems = @() foreach ($app in $wingetApps) { if ($PSCmdlet.ShouldProcess($app.displayName, "Remove app, groups, and remediations")) { Write-Host "`n=== Processing: $($app.displayName) ===" -ForegroundColor Cyan # 1. Find and delete associated groups Write-Host "Searching for associated groups..." -ForegroundColor Yellow try { # Groups have display names: "{AppName} Required" or "{AppName} Uninstall" # Groups have descriptions: "Install group for {AppName} - ..." or "Uninstall group for {AppName} - ..." $installGroupName = "$($app.displayName) Required" $uninstallGroupName = "$($app.displayName) Uninstall" $escapedInstallName = $installGroupName.Replace("'", "''") $escapedUninstallName = $uninstallGroupName.Replace("'", "''") $groupsUri = "beta/groups?`$filter=displayName eq '$escapedInstallName' or displayName eq '$escapedUninstallName'" $groups = (Invoke-MgGraphRequest -Uri $groupsUri -Method GET).value foreach ($group in $groups) { try { $deleteGroupUri = "beta/groups/$($group.id)" Invoke-MgGraphRequest -Uri $deleteGroupUri -Method DELETE | Out-Null Write-Host " Deleted group: $($group.displayName)" -ForegroundColor Green $deletedGroups++ } catch { Write-Warning "Failed to delete group $($group.displayName): $_" $failedItems += "Group: $($group.displayName)" } } } catch { Write-Warning "Error searching for groups: $_" } # 2. Find and delete associated Proactive Remediation Write-Host "Searching for associated Proactive Remediation..." -ForegroundColor Yellow try { # Remediations have display names: "{AppName} Proactive Update" # Remediations have descriptions: "Auto-update remediation for {AppName} - ..." $remediationName = "$($app.displayName) Proactive Update" $escapedRemediationName = $remediationName.Replace("'", "''") $remediationsUri = "beta/deviceManagement/deviceHealthScripts?`$filter=displayName eq '$escapedRemediationName'" $remediations = (Invoke-MgGraphRequest -Uri $remediationsUri -Method GET).value foreach ($remediation in $remediations) { try { $deleteRemediationUri = "beta/deviceManagement/deviceHealthScripts/$($remediation.id)" Invoke-MgGraphRequest -Uri $deleteRemediationUri -Method DELETE | Out-Null Write-Host " Deleted remediation: $($remediation.displayName)" -ForegroundColor Green $deletedRemediations++ } catch { Write-Warning "Failed to delete remediation $($remediation.displayName): $_" $failedItems += "Remediation: $($remediation.displayName)" } } } catch { Write-Warning "Error searching for remediations: $_" } # 3. Delete the app Write-Host "Deleting app..." -ForegroundColor Yellow try { $deleteAppUri = "beta/deviceAppManagement/mobileApps/$($app.id)" Invoke-MgGraphRequest -Uri $deleteAppUri -Method DELETE | Out-Null Write-Host " Deleted app: $($app.displayName)" -ForegroundColor Green $deletedApps++ } catch { Write-Error "Failed to delete app $($app.displayName): $_" $failedItems += "App: $($app.displayName)" } } } # Summary Write-Host "`n=== Deletion Summary ===" -ForegroundColor Cyan Write-Host "Apps deleted: $deletedApps" -ForegroundColor $(if ($deletedApps -gt 0) { "Green" } else { "Gray" }) Write-Host "Groups deleted: $deletedGroups" -ForegroundColor $(if ($deletedGroups -gt 0) { "Green" } else { "Gray" }) Write-Host "Remediations deleted: $deletedRemediations" -ForegroundColor $(if ($deletedRemediations -gt 0) { "Green" } else { "Gray" }) if ($failedItems.Count -gt 0) { Write-Host "`nFailed deletions: $($failedItems.Count)" -ForegroundColor Red $failedItems | ForEach-Object { Write-Host " - $_" -ForegroundColor Red } } else { Write-Host "`nAll items deleted successfully!`n" -ForegroundColor Green } } |