Identifying missing servers for Defender for Identity
Microsoft Defender for Identity is mostly associated with Domain Controllers, besides this, it also supports:
- Entra Connect Servers
- ADFS Servers
- ADCS Servers
Sometimes, it is difficult to know what servers are still to be onboarded.
Using the portal
Using the Security Portal, it is pretty easy to identify to be onboarded servers as covered in this video below.
Go into the security portal > select secure score and search ‘Install Defender for Identity’ in the search bar. This will show all open recommendations about missing servers.
If there is no recommendation for a specific type of server, this means it is not present in your environment.
Using Powershell
If you to automate this, you can retrieve the secure score using Powershell. In order to filter, you need to know the ‘controlNames’. They aren’t really present in the UI, so it takes a bit of searching to find the correct one.
Below is a script that retrieves what servers are missing and provides you with a score according to your coverage.
Connect-MgGraph -Scopes 'SecurityEvents.Read.All'
$MDIOnboardingControlNames = @(
"AATP_Sensor",
"AATP_AdcsComputersWithNoMdiSensorInstalled",
"AATP_AdfsComputersWithNoMdiSensorInstalled",
"AATP_EntraConnectComputersWithNoMdiSensorInstalled"
)
$MDINotOnboardedControlName = "AATP_DefenderForIdentityIsNotInstalled"
$responseScore = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/security/secureScores?`$top=1" -Headers $headers
$MDIOnboardingControls = $responseScore.Value.controlScores | Where-Object { $_.ControlName -in $MDIOnboardingControlNames }
$MDINotOnboardedControl = $responseScore.Value.controlScores | Where-Object { $_.ControlName -eq $MDINotOnboardedControlName }
$totalScores = 0
$readableControls = @()
foreach ($MDIOnboardingControl in $MDIOnboardingControls) {
if ($MDIOnboardingControl.ControlName -eq "AATP_Sensor") {
$totalScores += ($MDIOnboardingControl.scoreInPercentage * 2)
$scoreValue = ($MDIOnboardingControl.scoreInPercentage * 2)
}
else {
$totalScores += $MDIOnboardingControl.scoreInPercentage
$scoreValue = $MDIOnboardingControl.scoreInPercentage
}
$readableControls += [PSCustomObject]@{
ControlName = $MDIOnboardingControl.ControlName
Score = $scoreValue
}
}
$weightedScore = $totalScores / 5
switch ($weightedScore) {
{ $_ -le 50 } {
$mdiStatus = "π’"
break
}
{ $_ -le 70 } {
$mdiStatus = "π"
break
}
{ $_ -le 100 } {
$mdiStatus = "π"
break
}
"100.0" {
$mdiStatus = "π"
}
}
$mdiControlNameMap = @{
"AATP_Sensor" = "Domain Controller"
"AATP_AdcsComputersWithNoMdiSensorInstalled" = "ADCS"
"AATP_AdfsComputersWithNoMdiSensorInstalled" = "ADFS"
"AATP_EntraConnectComputersWithNoMdiSensorInstalled" = "Entra Connect"
}
$mdiMissingServers = @()
foreach ($control in $MDIOnboardingControls) {
$total = $control.total
$count = $control.count
$controlName = $control.ControlName
$readableName = $mdiControlNameMap[$controlName]
$missingServers = $total - $count
if ($missingServers -gt 0) {
$mdiMissingServers += [PSCustomObject]@{
Control = $readableName
MissingServers = $missingServers
}
}
}
Write-Host "Overall MDI Implementation Status: $mdiStatus ($([math]::Round($weightedScore, 2))%)"
$implementationStatus = $MDINotOnboardedControl.on
if ($implementationStatus -eq $false) {
Write-Host "Defender for Identity deployment has not been started yet."
}
else {
if ($mdiMissingServers.Count -gt 0) {
foreach ($row in $mdiMissingServers) {
Write-Host "$($row.MissingServers) $($row.Control) servers need to have the MDI sensor installed."
}
}
}
Categories