{"id":9523,"date":"2026-04-01T02:09:14","date_gmt":"2026-04-01T02:09:14","guid":{"rendered":"https:\/\/pariswells.com\/blog\/?p=9523"},"modified":"2026-04-01T02:09:15","modified_gmt":"2026-04-01T02:09:15","slug":"script-to-get-list-of-machines-not-enrolled-into-defender-but-enrolled-into-intune","status":"publish","type":"post","link":"https:\/\/pariswells.com\/blog\/research\/script-to-get-list-of-machines-not-enrolled-into-defender-but-enrolled-into-intune","title":{"rendered":"Script to get list of Machines not enrolled into Defender but enrolled into Intune"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code class=\"\">&lt;#\n.SYNOPSIS\n    Gets all Intune enrolled devices not onboarded into Microsoft Defender for Endpoint.\n    Matches directly on azureADDeviceId (Intune) = aadDeviceId (Defender).\n\n.REQUIREMENTS\n    Install-Module Microsoft.Graph -Scope CurrentUser\n#>\n\n# ?? Configuration ??????????????????????????????????????????????????????????????\n$ExportCSV  = $true\n$ExportPath = \".\\IntuneNotInDefender_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv\"\n\n# ?? Login ??????????????????????????????????????????????????????????????????????\nWrite-Host \"Opening browser for login...\" -ForegroundColor Cyan\n\nConnect-MgGraph -Scopes @(\n    \"DeviceManagementManagedDevices.Read.All\",\n    \"SecurityEvents.Read.All\",\n    \"ThreatHunting.Read.All\"\n) -NoWelcome\n\nWrite-Host \"  Logged in as: $((Get-MgContext).Account)\" -ForegroundColor Green\n\n# ?? Step 1: Get all Defender machines via Advanced Hunting ?????????????????????\n# Uses the DeviceInfo table which contains AadDeviceId for all onboarded machines\nWrite-Host \"`nFetching Defender onboarded devices via Advanced Hunting...\" -ForegroundColor Cyan\n\n$mdeLookup = @{}\n\n$huntingBody = @{\n    Query = @\"\nDeviceInfo\n| where isnotempty(AadDeviceId)\n| summarize arg_max(Timestamp, *) by AadDeviceId\n| project AadDeviceId, DeviceName\n\"@\n} | ConvertTo-Json\n\ntry {\n    $huntingResponse = Invoke-MgGraphRequest `\n        -Uri \"https:\/\/graph.microsoft.com\/v1.0\/security\/runHuntingQuery\" `\n        -Method POST `\n        -Body $huntingBody `\n        -ContentType \"application\/json\" `\n        -ErrorAction Stop\n\n    foreach ($row in $huntingResponse.results) {\n        if ($row.AadDeviceId) {\n            $mdeLookup[$row.AadDeviceId.ToLower()] = $row.DeviceName\n        }\n    }\n    Write-Host \"  Found $($mdeLookup.Count) Defender onboarded devices\" -ForegroundColor Green\n}\ncatch {\n    # Fallback: try beta listMachines endpoint\n    Write-Host \"  Hunting query failed, trying beta machines endpoint...\" -ForegroundColor Yellow\n\n    $uri = \"https:\/\/graph.microsoft.com\/beta\/security\/microsoft.graph.security.listMachines()?`$select=aadDeviceId,computerDnsName&amp;`$top=999\"\n    do {\n        $response = Invoke-MgGraphRequest -Uri $uri -Method GET -ErrorAction Stop\n        foreach ($m in $response.value) {\n            if ($m.aadDeviceId) {\n                $mdeLookup[$m.aadDeviceId.ToLower()] = $m.computerDnsName\n            }\n        }\n        $uri = $response.'@odata.nextLink'\n    } while ($uri)\n\n    Write-Host \"  Found $($mdeLookup.Count) Defender onboarded devices\" -ForegroundColor Green\n}\n\nif ($mdeLookup.Count -eq 0) {\n    Write-Error \"Could not retrieve any Defender devices. Check that SecurityEvents.Read.All or ThreatHunting.Read.All is consented in your tenant.\"\n    Disconnect-MgGraph\n    exit 1\n}\n\n# ?? Step 2: Get all Intune managed devices ?????????????????????????????????????\nWrite-Host \"Fetching Intune enrolled devices...\" -ForegroundColor Cyan\n\n$intuneDevices = [System.Collections.Generic.List[object]]::new()\n$uri = \"https:\/\/graph.microsoft.com\/v1.0\/deviceManagement\/managedDevices?\" +\n       \"`$select=id,deviceName,operatingSystem,osVersion,userPrincipalName,\" +\n       \"serialNumber,azureADDeviceId,lastSyncDateTime,complianceState,managedDeviceOwnerType&amp;`$top=999\"\n\ndo {\n    $response = Invoke-MgGraphRequest -Uri $uri -Method GET\n    $intuneDevices.AddRange($response.value)\n    $uri = $response.'@odata.nextLink'\n} while ($uri)\n\nWrite-Host \"  Found $($intuneDevices.Count) Intune devices\" -ForegroundColor Green\n\n# ?? Step 3: Compare directly ???????????????????????????????????????????????????\n# Intune.azureADDeviceId == Defender.AadDeviceId \u2014 direct match, no translation\nWrite-Host \"`nComparing...\" -ForegroundColor Cyan\n\n$results = foreach ($device in $intuneDevices) {\n    $inDefender = $device.azureADDeviceId -and\n                  $mdeLookup.ContainsKey($device.azureADDeviceId.ToLower())\n\n    if (-not $inDefender) {\n        [PSCustomObject]@{\n            DeviceName        = $device.deviceName\n            OS                = $device.operatingSystem\n            OSVersion         = $device.osVersion\n            UserPrincipalName = $device.userPrincipalName\n            SerialNumber      = $device.serialNumber\n            IntuneDeviceId    = $device.id\n            AzureADDeviceId   = $device.azureADDeviceId\n            LastSync          = $device.lastSyncDateTime\n            ComplianceState   = $device.complianceState\n            OwnerType         = $device.managedDeviceOwnerType\n        }\n    }\n}\n\n# ?? Output ?????????????????????????????????????????????????????????????????????\nWrite-Host \"`n???????????????????????????????????????????????????\" -ForegroundColor Yellow\nWrite-Host \"  Total Intune devices:           $($intuneDevices.Count)\" -ForegroundColor White\nWrite-Host \"  Defender onboarded:             $($mdeLookup.Count)\"     -ForegroundColor White\nWrite-Host \"  In Intune but NOT in Defender:  $($results.Count)\"       -ForegroundColor Red\nWrite-Host \"???????????????????????????????????????????????????\" -ForegroundColor Yellow\n\n$results | Format-Table DeviceName, OS, UserPrincipalName, AzureADDeviceId -AutoSize\n\nif ($ExportCSV -and $results.Count -gt 0) {\n    $results | Export-Csv -Path $ExportPath -NoTypeInformation -Encoding UTF8\n    Write-Host \"`nExported to: $ExportPath\" -ForegroundColor Green\n}\n\nWrite-Host \"`nBreakdown by OS:\" -ForegroundColor Cyan\n$results | Group-Object OS | Sort-Object Count -Descending | Format-Table Name, Count -AutoSize\n\nDisconnect-MgGraph<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-9523","post","type-post","status-publish","format-standard","hentry","category-research"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/posts\/9523","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/comments?post=9523"}],"version-history":[{"count":1,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/posts\/9523\/revisions"}],"predecessor-version":[{"id":9524,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/posts\/9523\/revisions\/9524"}],"wp:attachment":[{"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/media?parent=9523"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/categories?post=9523"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/tags?post=9523"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}