Managing devices in Intune often involves remote actions like wiping lost or retired devices. While Intune makes these actions straightforward, tracking and auditing them can be confusing, especially if the device record is deleted after the wipe. In this post, we’ll walk through how to trace a wiped device using the Intune admin portal, tenant audit logs, and the Device Actions report.
1. Tenant Admin Portal: Where It All Begins
When you initiate a device wipe, Intune logs the activity in the Tenant Audit Logs. You can access these logs via:
Intune Admin Center → Tenant administration → Audit logs
Filter by:
- Category: Device
- Activity Type:
wipe ManagedDevice - Initiated By: The user who triggered the wipe
Here’s an example log entry:
Activity: wipe ManagedDevice
Date: Fri, 03 Oct 2025 10:02:52 GMT
Initiated By: mr.wipe@croucher.cloud
Target ObjectID: a1b6a0d6-5f55-4e45-9baa-ded1e0700b55
Status: Success
At first glance, the log gives you the ObjectID of the device and the user who initiated the wipe. However, it does not directly show the device name, which can be confusing if the device has been deleted.
2. Understanding Audit Logs and the Wipe Action
The wipe ManagedDevice activity is recorded as an action in the audit logs, including details such as:
- Operation Type: Action
- Status: Success or Failure
- Modified Properties: For example,
keepEnrollmentData = False
The ObjectID uniquely identifies the device in Intune. If the device still exists, you could search for this ID in Devices → All devices. But if the device has been fully wiped and the record removed, the ObjectID no longer resolves to a live device.
3. Device Name After Deletion: The Device Actions Report
Here’s where Intune makes up for that limitation. Even if the device record is gone, you can still find its friendly name via:
Intune Admin Center → Devices → Monitor → Device Actions
Steps:
- Filter by Action = Wipe
- Filter by Initiated By = the user who triggered the wipe
- Look at the Device Name column
The Device Actions report retains historical information, including the device name, user, and timestamp. This allows you to correlate the ObjectID in the audit logs with the actual device name before deletion.
4. Correlation IDs: The Quirk
One interesting observation is that the Correlation ID in the tenant audit log for the wipe request does not match the correlation ID in the Entra (Azure AD) audit logs.
Why?
- Intune generates its own correlation ID for device actions internally.
- Entra/Azure AD generates a separate correlation ID for directory-level events.
- These IDs are not synchronized, which means you cannot rely on a single correlation ID to trace an action across both systems. Instead, use the ObjectID / Device Name / Timestamp as the common thread.
Script and HTML Report
This looks like a good opportunity to take the information above and using a App Registration create a Powershell script to complete the actions above and then produce a nice HTML report along with a CSV file as well.
API Permissions required
DeviceManagementManagedDevices.Read.All - Read managed devices
DeviceManagementServiceConfig.Read.All - Read Intune configuration
DeviceManagementConfiguration.Read.All - Read device configurations
AuditLog.Read.All - Read directory audit logs
User.Read.All - Read user profiles
Script : wipe-report.ps1
Activity: wipe ManagedDevice#Requires -Version 5.1
<#
.SYNOPSIS
Intune Device Wipe Report - Finding Initiators Including Allan Young
.DESCRIPTION
Uses multiple methods to find who initiated wipes, including beta endpoints
#>
# ============================================================================
# CONFIGURATION
# ============================================================================
$TenantId = "<tenant-id>"
$ClientId = "<client-id>"
$ClientSecret = "<client-secret>"
$Days = 30
$OutputPath = (Get-Location).Path
# ============================================================================
# MAIN SCRIPT - MULTIPLE METHODS TO FIND INITIATORS
# ============================================================================
Write-Host "`n╔══════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
Write-Host "║ Intune Device Wipe Report - Finding All Initiators ║" -ForegroundColor Cyan
Write-Host "╚══════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
try {
# Get token
Write-Host "`nStep 1: Authenticating..." -ForegroundColor Yellow
$body = @{
client_id = $ClientId
client_secret = $ClientSecret
scope = "https://graph.microsoft.com/.default"
grant_type = "client_credentials"
}
$tokenResponse = Invoke-RestMethod `
-Method Post `
-Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" `
-Body $body `
-ContentType "application/x-www-form-urlencoded"
$headers = @{
"Authorization" = "Bearer $($tokenResponse.access_token)"
}
Write-Host "✓ Authentication successful" -ForegroundColor Green
# Method 1: Try beta remoteActionAudits endpoint
Write-Host "`nStep 2: Trying to get remote action audits (beta)..." -ForegroundColor Yellow
$remoteActions = @()
try {
$uri = "https://graph.microsoft.com/beta/deviceManagement/remoteActionAudits"
$response = Invoke-RestMethod -Uri $uri -Headers $headers -Method GET -ErrorAction SilentlyContinue
if ($response.value) {
$remoteActions = $response.value
Write-Host "✓ Retrieved $($remoteActions.Count) remote action audits!" -ForegroundColor Green
# Show sample of what we found
$wipeActions = $remoteActions | Where-Object { $_.action -match "wipe|retire" }
if ($wipeActions) {
Write-Host " Found $($wipeActions.Count) wipe/retire actions" -ForegroundColor Cyan
$initiators = $wipeActions | Select-Object -ExpandProperty initiatedByUserPrincipalName -Unique
Write-Host " Initiators found: $($initiators -join ', ')" -ForegroundColor Green
}
}
}
catch {
Write-Host " ✗ Cannot access remoteActionAudits (beta)" -ForegroundColor Yellow
}
# Method 2: Try v1.0 with expanded query
if ($remoteActions.Count -eq 0) {
Write-Host "`nTrying deviceManagement audit events with different approach..." -ForegroundColor Yellow
try {
# Try without filter first
$uri = "https://graph.microsoft.com/v1.0/deviceManagement/auditEvents"
$response = Invoke-RestMethod -Uri $uri -Headers $headers -Method GET -ErrorAction SilentlyContinue -TimeoutSec 5
if ($response.value) {
Write-Host "✓ SUCCESS! Retrieved $($response.value.Count) Intune audit events!" -ForegroundColor Green
# Get all pages
$allAuditEvents = @()
$allAuditEvents += $response.value
while ($response.'@odata.nextLink') {
$response = Invoke-RestMethod -Uri $response.'@odata.nextLink' -Headers $headers -Method GET
$allAuditEvents += $response.value
Write-Host " Retrieved $($allAuditEvents.Count) events so far..." -ForegroundColor Gray
}
# Filter for wipe events
$wipeEvents = $allAuditEvents | Where-Object {
$_.activity -match "wipe|retire" -or
$_.activityDisplayName -match "wipe|retire" -or
$_.activityType -match "wipe|retire"
}
Write-Host "✓ Found $($wipeEvents.Count) wipe/retire events in Intune audit!" -ForegroundColor Green
}
}
catch {
Write-Host " ✗ Still cannot access deviceManagement/auditEvents" -ForegroundColor Yellow
}
}
# Method 3: Get all managed devices
Write-Host "`nStep 3: Getting all managed devices..." -ForegroundColor Yellow
$allDevices = @()
$uri = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices"
do {
$response = Invoke-RestMethod -Uri $uri -Headers $headers -Method GET
if ($response.value) {
$allDevices += $response.value
}
$uri = $response.'@odata.nextLink'
} while ($uri)
Write-Host "✓ Retrieved $($allDevices.Count) managed devices" -ForegroundColor Green
# Method 4: Try directory audit logs for device operations
Write-Host "`nStep 4: Checking directory audit logs for device operations..." -ForegroundColor Yellow
$directoryAudits = @()
# Search for device-related audit events
$filters = @(
"targetResources/any(t: t/type eq 'Device')",
"category eq 'Device'"
)
foreach ($filter in $filters) {
try {
$encodedFilter = [System.Web.HttpUtility]::UrlEncode($filter)
$uri = "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?`$filter=$encodedFilter&`$top=999"
$response = Invoke-RestMethod -Uri $uri -Headers $headers -Method GET -ErrorAction SilentlyContinue -TimeoutSec 10
if ($response.value) {
$directoryAudits += $response.value
}
}
catch {
# Continue with next filter
}
}
# Also get recent directory audits without filter
try {
$startDate = (Get-Date).AddDays(-$Days).ToString("yyyy-MM-dd")
$uri = "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?`$filter=activityDateTime ge $startDate&`$top=999"
$response = Invoke-RestMethod -Uri $uri -Headers $headers -Method GET -TimeoutSec 10
if ($response.value) {
$deviceAudits = $response.value | Where-Object {
$_.category -eq "Device" -or
$_.activityDisplayName -match "device|wipe|retire" -or
($_.targetResources -and $_.targetResources.type -contains "Device")
}
$directoryAudits += $deviceAudits
}
}
catch {
# Continue
}
Write-Host "✓ Retrieved $($directoryAudits.Count) directory audit events" -ForegroundColor Green
# Process all data sources
Write-Host "`nStep 5: Processing and combining all data sources..." -ForegroundColor Yellow
$reportData = @()
$cutoffDate = (Get-Date).AddDays(-$Days)
# Process remote action audits if we have them
if ($remoteActions.Count -gt 0) {
foreach ($action in $remoteActions) {
if ($action.action -match "wipe|retire|delete|remoteLock|factoryReset") {
$actionDate = if ($action.requestDateTime) { [DateTime]$action.requestDateTime } else { [DateTime]::MinValue }
if ($actionDate -ge $cutoffDate) {
$reportData += [PSCustomObject]@{
DateTime = $actionDate.ToString("yyyy-MM-dd HH:mm:ss")
DeviceName = $action.deviceDisplayName
DeviceId = $action.managedDeviceId
UserEmail = $action.userPrincipalName
Action = $action.action
Status = $action.actionState
InitiatedBy = $action.initiatedByUserPrincipalName
RequestId = $action.id
Source = "Remote Action Audit"
}
}
}
}
Write-Host "✓ Processed $($reportData.Count) remote action audits with initiators!" -ForegroundColor Green
}
# Process Intune audit events if we have them
if ($wipeEvents.Count -gt 0) {
foreach ($event in $wipeEvents) {
$eventDate = [DateTime]$event.activityDateTime
if ($eventDate -ge $cutoffDate) {
$initiator = "Unknown"
if ($event.actor) {
if ($event.actor.userPrincipalName) {
$initiator = $event.actor.userPrincipalName
} elseif ($event.actor.applicationDisplayName) {
$initiator = $event.actor.applicationDisplayName
}
}
$deviceName = "Unknown"
$deviceId = ""
if ($event.resources) {
$deviceResource = $event.resources | Where-Object { $_.type -like "*Device*" } | Select-Object -First 1
if ($deviceResource) {
$deviceName = $deviceResource.displayName
$deviceId = $deviceResource.resourceId
}
}
# Check if we already have this from remote actions
$exists = $reportData | Where-Object {
$_.DeviceId -eq $deviceId -and
[Math]::Abs(([DateTime]$_.DateTime - $eventDate).TotalMinutes) -lt 60
}
if (-not $exists) {
$reportData += [PSCustomObject]@{
DateTime = $eventDate.ToString("yyyy-MM-dd HH:mm:ss")
DeviceName = $deviceName
DeviceId = $deviceId
UserEmail = ""
Action = if ($event.activity) { $event.activity } else { $event.activityDisplayName }
Status = if ($event.activityResult) { $event.activityResult } else { "Success" }
InitiatedBy = $initiator
RequestId = $event.id
Source = "Intune Audit"
}
}
}
}
Write-Host "✓ Processed Intune audit events with initiators!" -ForegroundColor Green
}
# Process directory audits
$initiatorLookup = @{}
foreach ($audit in $directoryAudits) {
if ($audit.initiatedBy -and $audit.targetResources) {
foreach ($resource in $audit.targetResources) {
if ($resource.type -eq "Device" -and $resource.displayName) {
$key = $resource.displayName.ToLower()
$initiator = "Unknown"
if ($audit.initiatedBy.user.userPrincipalName) {
$initiator = $audit.initiatedBy.user.userPrincipalName
} elseif ($audit.initiatedBy.app.displayName) {
$initiator = $audit.initiatedBy.app.displayName
}
$initiatorLookup[$key] = @{
Initiator = $initiator
Date = [DateTime]$audit.activityDateTime
Activity = $audit.activityDisplayName
}
}
}
}
}
Write-Host " Built initiator lookup with $($initiatorLookup.Count) entries" -ForegroundColor Gray
# Process devices with wipe/retire status
foreach ($device in $allDevices) {
# Check device action results
if ($device.deviceActionResults -and $device.deviceActionResults.Count -gt 0) {
foreach ($action in $device.deviceActionResults) {
if ($action.actionName -match "wipe|retire|delete|remoteLock|factoryReset") {
$actionDate = [DateTime]$action.startDateTime
if ($actionDate -ge $cutoffDate) {
# Try to find initiator
$initiator = "Unknown"
$deviceNameLower = $device.deviceName.ToLower()
# Check our lookup table
if ($initiatorLookup.ContainsKey($deviceNameLower)) {
$lookupInfo = $initiatorLookup[$deviceNameLower]
# Check if dates are close (within 24 hours)
if ([Math]::Abs(($lookupInfo.Date - $actionDate).TotalHours) -lt 24) {
$initiator = $lookupInfo.Initiator
}
}
# Check if we already have this event
$exists = $reportData | Where-Object {
$_.DeviceName -eq $device.deviceName -and
[Math]::Abs(([DateTime]$_.DateTime - $actionDate).TotalMinutes) -lt 60
}
if (-not $exists) {
$reportData += [PSCustomObject]@{
DateTime = $actionDate.ToString("yyyy-MM-dd HH:mm:ss")
DeviceName = $device.deviceName
DeviceId = $device.id
UserEmail = $device.userPrincipalName
Action = $action.actionName
Status = $action.actionState
InitiatedBy = $initiator
RequestId = ""
Source = "Device Action"
}
}
}
}
}
}
# Check management state
if ($device.managementState -match "wipe|retire") {
$exists = $reportData | Where-Object { $_.DeviceName -eq $device.deviceName }
if (-not $exists) {
$initiator = "Unknown"
$deviceNameLower = $device.deviceName.ToLower()
if ($initiatorLookup.ContainsKey($deviceNameLower)) {
$initiator = $initiatorLookup[$deviceNameLower].Initiator
}
$reportData += [PSCustomObject]@{
DateTime = ([DateTime]$device.lastSyncDateTime).ToString("yyyy-MM-dd HH:mm:ss")
DeviceName = $device.deviceName
DeviceId = $device.id
UserEmail = $device.userPrincipalName
Action = "Device " + $device.managementState
Status = "Completed"
InitiatedBy = $initiator
RequestId = ""
Source = "Device State"
}
}
}
}
# Sort by date
$reportData = $reportData | Sort-Object DateTime -Descending
# Statistics
$totalEvents = $reportData.Count
$knownInitiators = ($reportData | Where-Object { $_.InitiatedBy -ne "Unknown" }).Count
$unknownInitiators = ($reportData | Where-Object { $_.InitiatedBy -eq "Unknown" }).Count
$uniqueInitiators = $reportData | Where-Object { $_.InitiatedBy -ne "Unknown" } | Select-Object -ExpandProperty InitiatedBy -Unique
Write-Host "`n╔══════════════════════════════════════════════════════════╗" -ForegroundColor Green
Write-Host "║ RESULTS SUMMARY ║" -ForegroundColor Green
Write-Host "╚══════════════════════════════════════════════════════════╝" -ForegroundColor Green
Write-Host "`n📊 Statistics:" -ForegroundColor Cyan
Write-Host " • Total wipe/retire events: $totalEvents" -ForegroundColor White
Write-Host " • Events with known initiator: $knownInitiators" -ForegroundColor Green
Write-Host " • Events with unknown initiator: $unknownInitiators" -ForegroundColor Yellow
if ($uniqueInitiators.Count -gt 0) {
Write-Host "`n👥 Initiators Found:" -ForegroundColor Cyan
foreach ($initiator in $uniqueInitiators) {
$count = ($reportData | Where-Object { $_.InitiatedBy -eq $initiator }).Count
Write-Host " • $initiator ($count events)" -ForegroundColor White
}
}
# Generate detailed HTML report
Write-Host "`nStep 6: Generating HTML report..." -ForegroundColor Yellow
$html = @"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Intune Device Wipe Report - With Initiators</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f5f5f7;
padding: 20px;
}
.container {
max-width: 1800px;
margin: 0 auto;
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 40px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
font-weight: 300;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.header .subtitle {
opacity: 0.95;
font-size: 1.1em;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
padding: 30px;
background: linear-gradient(135deg, #667eea10 0%, #764ba210 100%);
border-bottom: 1px solid #e1e4e8;
}
.stat {
background: white;
padding: 25px;
border-radius: 10px;
text-align: center;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
border: 1px solid #e1e4e8;
transition: transform 0.2s;
}
.stat:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.stat-value {
font-size: 2.8em;
font-weight: 700;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
display: block;
}
.stat-label {
font-size: 0.9em;
color: #586069;
margin-top: 8px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.initiators-section {
margin: 20px 30px;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid #667eea;
}
.initiators-section h3 {
color: #667eea;
margin-bottom: 15px;
}
.initiator-item {
display: inline-block;
margin: 5px;
padding: 8px 16px;
background: white;
border-radius: 20px;
border: 1px solid #e1e4e8;
font-size: 0.95em;
}
.initiator-count {
display: inline-block;
margin-left: 8px;
padding: 2px 8px;
background: #667eea;
color: white;
border-radius: 10px;
font-size: 0.85em;
font-weight: 600;
}
.search-container {
padding: 30px;
background: white;
}
.search-box {
width: 100%;
padding: 15px 25px;
font-size: 16px;
border: 2px solid #e1e4e8;
border-radius: 50px;
transition: all 0.3s ease;
}
.search-box:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102,126,234,0.1);
}
.warning-box {
margin: 20px 30px;
padding: 15px 20px;
background: #fff3cd;
border-left: 4px solid #ffc107;
border-radius: 4px;
color: #856404;
}
.success-box {
margin: 20px 30px;
padding: 15px 20px;
background: #d4edda;
border-left: 4px solid #28a745;
border-radius: 4px;
color: #155724;
}
.table-container {
overflow-x: auto;
padding: 0 30px 30px 30px;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.9em;
}
th {
background: #f6f8fa;
padding: 14px 8px;
text-align: left;
font-weight: 600;
font-size: 0.85em;
color: #586069;
text-transform: uppercase;
letter-spacing: 0.3px;
border-bottom: 2px solid #667eea;
position: sticky;
top: 0;
z-index: 10;
cursor: pointer;
white-space: nowrap;
}
th:hover {
background: #e9ecef;
}
td {
padding: 12px 8px;
border-bottom: 1px solid #f0f3f6;
color: #24292e;
}
tr:hover {
background: #f8f9fb;
}
.device-name {
font-weight: 600;
color: #667eea;
}
.initiator-known {
font-weight: 600;
color: #28a745;
}
.initiator-unknown {
color: #dc3545;
font-style: italic;
}
.status-done, .status-Completed, .status-Success {
color: #28a745;
font-weight: 600;
}
.status-failed {
color: #dc3545;
font-weight: 600;
}
.status-pending {
color: #ffc107;
font-weight: 600;
}
.source-badge {
display: inline-block;
padding: 3px 10px;
border-radius: 12px;
font-size: 0.8em;
font-weight: 600;
text-transform: uppercase;
}
.source-remote { background: #e3f2fd; color: #1976d2; }
.source-intune { background: #f3e5f5; color: #7b1fa2; }
.source-device { background: #e8f5e9; color: #388e3c; }
.source-directory { background: #fff3e0; color: #f57c00; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔍 Intune Device Wipe Report</h1>
<div class="subtitle">
Generated: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss") | Last $Days Days<br>
Complete Analysis with Initiator Discovery
</div>
</div>
<div class="stats">
<div class="stat">
<span class="stat-value">$totalEvents</span>
<div class="stat-label">Total Events</div>
</div>
<div class="stat">
<span class="stat-value">$knownInitiators</span>
<div class="stat-label">Known Initiators</div>
</div>
<div class="stat">
<span class="stat-value">$unknownInitiators</span>
<div class="stat-label">Unknown Initiators</div>
</div>
<div class="stat">
<span class="stat-value">$($uniqueInitiators.Count)</span>
<div class="stat-label">Unique Admins</div>
</div>
</div>
"@
# Add initiators section if we found any
if ($uniqueInitiators.Count -gt 0) {
$html += @"
<div class="initiators-section">
<h3>👥 Administrators Who Performed Wipes:</h3>
<div>
"@
foreach ($initiator in $uniqueInitiators) {
$count = ($reportData | Where-Object { $_.InitiatedBy -eq $initiator }).Count
$html += @"
<span class="initiator-item">
$initiator <span class="initiator-count">$count</span>
</span>
"@
}
$html += @"
</div>
</div>
"@
} else {
$html += @"
<div class="warning-box">
<strong>⚠ Warning:</strong> Could not retrieve initiator information. The Intune audit events API appears to be blocked.
Please check the Intune portal directly at: Tenant Administration → Audit logs
</div>
"@
}
$html += @"
<div class="search-container">
<input type="text" class="search-box" id="searchInput" placeholder="🔍 Search by device name, user, initiator, date, or any field..." onkeyup="filterTable()">
</div>
<div class="table-container">
"@
if ($reportData.Count -gt 0) {
$html += @"
<table id="dataTable">
<thead>
<tr>
<th onclick="sortTable(0)">Date/Time ↕</th>
<th onclick="sortTable(1)">Device Name ↕</th>
<th onclick="sortTable(2)">User Email ↕</th>
<th onclick="sortTable(3)">Action ↕</th>
<th onclick="sortTable(4)">Status ↕</th>
<th onclick="sortTable(5)">Initiated By ↕</th>
<th onclick="sortTable(6)">Source ↕</th>
</tr>
</thead>
<tbody>
"@
foreach ($row in $reportData) {
$statusClass = "status-$($row.Status)"
$initiatorClass = if ($row.InitiatedBy -eq "Unknown") { "initiator-unknown" } else { "initiator-known" }
# Determine source badge class
$sourceClass = "source-device"
if ($row.Source -like "*Remote*") { $sourceClass = "source-remote" }
elseif ($row.Source -like "*Intune*") { $sourceClass = "source-intune" }
elseif ($row.Source -like "*Directory*") { $sourceClass = "source-directory" }
$html += @"
<tr>
<td>$($row.DateTime)</td>
<td class="device-name">$($row.DeviceName)</td>
<td>$($row.UserEmail)</td>
<td>$($row.Action)</td>
<td class="$statusClass">$($row.Status)</td>
<td class="$initiatorClass">$($row.InitiatedBy)</td>
<td><span class="source-badge $sourceClass">$($row.Source)</span></td>
</tr>
"@
}
$html += "</tbody></table>"
} else {
$html += "<div style='text-align: center; padding: 40px; color: #999;'>No wipe or retire events found in the last $Days days</div>"
}
$html += @"
</div>
</div>
<script>
function filterTable() {
const input = document.getElementById('searchInput');
const filter = input.value.toUpperCase();
const table = document.getElementById('dataTable');
if (!table) return;
const tbody = table.getElementsByTagName('tbody')[0];
const rows = tbody.getElementsByTagName('tr');
for (let i = 0; i < rows.length; i++) {
const cells = rows[i].getElementsByTagName('td');
let found = false;
for (let j = 0; j < cells.length; j++) {
if (cells[j].textContent.toUpperCase().indexOf(filter) > -1) {
found = true;
break;
}
}
rows[i].style.display = found ? '' : 'none';
}
}
let sortDir = {};
function sortTable(n) {
const table = document.getElementById('dataTable');
if (!table) return;
const tbody = table.getElementsByTagName('tbody')[0];
const rows = Array.from(tbody.getElementsByTagName('tr'));
sortDir[n] = !sortDir[n];
rows.sort((a, b) => {
const x = a.getElementsByTagName('td')[n].textContent.toLowerCase();
const y = b.getElementsByTagName('td')[n].textContent.toLowerCase();
if (n === 0) { // Date column
return sortDir[n]
? new Date(x) - new Date(y)
: new Date(y) - new Date(x);
}
return sortDir[n] ? x.localeCompare(y) : y.localeCompare(x);
});
rows.forEach(row => tbody.appendChild(row));
}
</script>
</body>
</html>
"@
# Save HTML report
$htmlPath = Join-Path $OutputPath "IntuneWipeReport_$(Get-Date -Format 'yyyyMMdd_HHmmss').html"
$html | Out-File -FilePath $htmlPath -Encoding UTF8
# Also save CSV for data analysis
$csvPath = Join-Path $OutputPath "IntuneWipeReport_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
$reportData | Export-Csv -Path $csvPath -NoTypeInformation
Write-Host "`n✓ Reports generated:" -ForegroundColor Green
Write-Host " • HTML: $htmlPath" -ForegroundColor White
Write-Host " • CSV: $csvPath" -ForegroundColor White
# Show sample of data
Write-Host "`nSample of wipe events:" -ForegroundColor Cyan
$reportData | Select-Object -First 5 | Format-Table DateTime, DeviceName, Action, InitiatedBy, Source -AutoSize
if ($knownInitiators -eq 0) {
Write-Host "`n⚠ WARNING: Could not retrieve initiator information!" -ForegroundColor Red
Write-Host " This indicates the Intune audit events API is blocked." -ForegroundColor Yellow
Write-Host " You'll need to check the Intune portal manually for initiator details." -ForegroundColor Yellow
}
}
catch {
Write-Host "`n❌ ERROR: $($_.Exception.Message)" -ForegroundColor Red
Write-Host "Stack trace: $($_.ScriptStackTrace)" -ForegroundColor Gray
}
Visual Results
This is the resulting report from the Powershell script where you can the device the action and the initiator:
Conclusion
When tracking device wipes in Intune:
- Start with Tenant Audit Logs to see the action, initiator, and ObjectID.
- Look for "wipe ManagedDevice" in the audit logs to confirm success.
- Use Device Actions Report to retrieve the friendly name if the device has been deleted.
- Correlation ID behavior: Intune and Entra logs use separate IDs, so don’t expect a one-to-one match.
By following these steps, administrators can maintain full visibility over remote wipe actions, even when devices are removed from Intune.