Files
IntuneManagement/Public/Start-GraphBulkDelete.ps1

114 lines
4.2 KiB
PowerShell

function Start-GraphBulkDelete {
<#
.SYNOPSIS
Bulk-delete Intune policy objects.
.DESCRIPTION
Public, UI-independent driver for bulk delete. The WPF and Avalonia
bulk-delete forms are thin callers of this function (they own the
confirmation prompt); the same function can be invoked from a
scheduled task or pipeline.
DESTRUCTIVE: every object of the selected groups (matching the
optional name filter) is deleted from the signed-in tenant. There is
no confirmation in this driver - callers confirm before invoking.
Groups are processed in DESCENDING ImportOrder so dependents are
deleted before their dependencies.
.PARAMETER Filter
Name filter (literal substring, case-insensitive). Empty = delete
every object of the selected groups.
.PARAMETER PolicyGroup
Restrict the delete to these PolicyGroup IDs. Mandatory - bulk
deleting every group implicitly is too dangerous for a default.
.PARAMETER TokenId
Authentication token id. Defaults to the current default token.
.EXAMPLE
Start-GraphBulkDelete -PolicyGroup DeviceConfiguration -Filter "[Test]"
.OUTPUTS
PSCustomObject with summary statistics (Groups, Deleted, Duration).
#>
[CmdletBinding()]
param(
[string]
$Filter,
[Parameter(Mandatory = $true)]
[string[]]
$PolicyGroup,
[Int]
$TokenId = (Get-DefaultTokenId)
)
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$selection = Resolve-IntuneTargetSelectors -PolicyGroup $PolicyGroup -Caller 'Start-GraphBulkDelete'
$unknownSelectors = $selection.Unknown # ids from -PolicyGroup that matched nothing
$targetGroups = [System.Collections.Generic.List[object]]::new()
$targetGroups.AddRange([object[]]$selection.Groups)
if ($targetGroups.Count -eq 0) {
Write-Log "Bulk delete: no policy groups selected" 2
return [PSCustomObject]@{ Groups = 0; Deleted = 0; UnknownSelectors = $unknownSelectors; Duration = $stopwatch.Elapsed }
}
Write-Log "****************************************************************"
Write-Log "Start bulk delete"
Write-Log "****************************************************************"
$totalDeleted = 0
# Reverse import-order so dependents are deleted before their dependencies.
$orderedGroups = @($targetGroups | Sort-Object { ($_.PolicyTypes | Measure-Object ImportOrder -Minimum).Minimum } -Descending)
$groupTotal = $orderedGroups.Count
$groupIndex = 0
foreach ($grp in $orderedGroups) {
$groupIndex++
Write-Log "----------------------------------------------------------------"
Write-Log "Delete $($grp.Title) objects"
Write-Log "----------------------------------------------------------------"
try {
Write-Status `
-Text ("Bulk delete - {0} ({1} of {2})" -f $grp.Title, $groupIndex, $groupTotal) `
-Detail "Listing policies" `
-Force
$policies = @(Get-GraphPolicies -PolicyGroup $grp.ID -TokenId $TokenId)
if ($Filter) {
$policies = @($policies | Where-Object { $_.Name -match [RegEx]::Escape($Filter) })
}
if ($policies.Count -eq 0) {
Write-Log "No $($grp.Title) objects found"
continue
}
Write-Log "Deleting $($policies.Count) $($grp.Title) object(s)"
Write-Status -Detail ("Deleting {0} object(s)" -f $policies.Count) -SkipLog -Force
$policies | Remove-GraphPolicy -Confirm:$false | Out-Null
$totalDeleted += $policies.Count
}
catch {
Write-LogError "Failed when deleting $($grp.Title) objects" $_.Exception
}
}
Write-Status $null
Write-Log "****************************************************************"
Write-Log "Bulk delete finished"
Write-Log "****************************************************************"
return [PSCustomObject]@{
Groups = $orderedGroups.Count
Deleted = $totalDeleted
UnknownSelectors = $unknownSelectors
Duration = $stopwatch.Elapsed
}
}