Public/Remove-TripwireDecoy.ps1

<#
.SYNOPSIS
    Remove a decoy from the tenant and from the inventory.

.DESCRIPTION
    Refuses any object id that is not already in the local inventory. This is the guard
    that keeps a deception tool from becoming a deletion tool: the only objects it can
    delete are ones it recorded itself as bait, so a typo, a copied guid or a hostile
    inventory edit cannot turn into a deleted employee.

.PARAMETER Id
    The decoy id from Get-TripwireDecoy.

.PARAMETER KeepObject
    Drop the decoy from the inventory without deleting anything in the tenant.

.EXAMPLE
    Remove-TripwireDecoy -Id decoy-8f21ab3c9d40 -WhatIf
#>

function Remove-TripwireDecoy {
    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([pscustomobject])]
    param(
        [Parameter(Mandatory)] [string] $Id,
        [switch] $KeepObject,
        [string] $Path
    )

    if (-not $Path) { $Path = Get-TripwireStatePath -Name 'decoys.json' }

    $all = @(Get-TripwireDecoy -Path $Path)
    $target = @($all | Where-Object { [string]$_.id -eq $Id })
    if ($target.Count -eq 0) {
        throw "'$Id' is not in the decoy inventory at $Path. EntraTripwire will only delete objects it recorded as decoys."
    }
    $decoy = $target[0]

    if (-not $KeepObject -and -not [string]::IsNullOrWhiteSpace([string]$decoy.objectId)) {
        # Deliberately NOT named $path: PowerShell variables are case-insensitive, so that
        # would silently overwrite the $Path parameter and write the inventory to a Graph URL.
        $graphPath = if ($decoy.type -eq 'User') { "/v1.0/users/$($decoy.objectId)" } else { "/v1.0/applications/$($decoy.objectId)" }
        if ($PSCmdlet.ShouldProcess("$($decoy.type) '$($decoy.displayName)' ($($decoy.objectId))", 'Delete the decoy object from the tenant')) {
            Invoke-TripwireGraphWrite -Method DELETE -Path $graphPath | Out-Null
        }
    }

    $remaining = @($all | Where-Object { [string]$_.id -ne $Id })
    if ($PSCmdlet.ShouldProcess($Path, "Remove decoy $Id from the inventory")) {
        @{ version = 1; decoys = $remaining } | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $Path -Encoding utf8
    }

    return $decoy
}