This article is contributed. See the original author and article here.

Welcome to the third and final blog post in our series on how to use tagging effectively in Microsoft Defender for Endpoint. We hope you’ve enjoyed this series and look forward to your feedback on this topic and what you’d like to see in the future.

Tagging using the API

Microsoft Defender for Endpoint APIs allow you to do many things through scripting to both query and change elements within your Microsoft Defender for Endpoint instance.  As part of this blog on tagging we wanted cover how you can use scripting to apply tags to machines directly using an API.

Within Advanced Hunting you can create a custom detection that runs the query on a regular basis to generate an alert.  You can also enable response actions as a result of this detection to affect the machines contained in the results:


You will notice however that tagging the resultant machines is not one of the options available.  Instead, it is possible to take the advanced hunting query and use it as an input to the script that applies the tag through the API.

Setting up API access

Before you can use PowerShell to query against the API you need to set up the API application in Azure.

In the Azure Active Directory section of you need to click on new App Registration and create a new app:


Once you have completed this part you will be presented with the following screen:


Take a note of the Application ID and the Directory ID, you will need these for your script.  Then click on “View API permissions”.  It is here that you define how the API can be accessed.

  1. Select “Add a permission”

  2. Click “APIs my organization uses”

  3. Type “Windows” into the search box and then select the “WindowsDefenderATP” API


When accessing the API, it is possible to use either user permissions or application permissions.  Using application permissions means that it doesn’t matter who is logged in to run the script and instead utilises the client secret to authenticate against the application.

For the purposes of what we are enabling we need specific permissions set.  We are running an Advance Hunting query so we need the “AdvanceQuery.Read.All” permission and we are also applying a tag to the machine so we need the “Machine.ReadWrite.All”



If you are using this scripting method for other actions, i.e. isolating a machine, then you would need to apply the appropriate permissions.

The final stage of the application registration is to create the client secret that will be used for authenticating.

In the app properties, click onto “Certificates & secrets” and create a new secret:


Then take note of the client secret that is created as you will need this alongside your Application ID and Directory ID for your script:


Now that you have your application created you can use PowerShell scripting to query against it and then write a tag back on the devices in the results.


Using an Advanced Hunting query for your tagging criteria

Advanced Hunting in Microsoft Defender for Endpoint is a powerful query tool that allows you to create complex queries based upon the telemetry that is gathered from the managed endpoints.  When writing these queries, it is possible to enable them as a custom detection, meaning they run at a regular interval and can apply actions against any device presented in the results.  However, there are only certain actions that can be applied against these devices and tagging isn’t one of them:



Therefore, if you want to tag a device based upon a query then you need to utilise the API.  Let’s say for example if you want to tag all devices in a certain subnet, the first step is to create the Advanced Hunting script:



| mvexpand parse_json(IPAddresses)

//| Subnet=IPAddresses.SubnetPrefix

| where IPAddresses contains “192.168.254” and IPAddresses.SubnetPrefix contains “24”

| summarize by DeviceId

| project DeviceId


Obviously, you can use pretty much any Advanced Hunting query in this test file, but it does need to return DeviceID in the results in order for it to be used in the next step.

Run the script first in the portal just to verify it is finding the correct data for you then copy the query into a text file to use as input to your API script.

The script below takes the query text file and then applies a tag of “DataCenter” against the DeviceIDs that are found by the query:


#Script to take a file containing an Advanced Hunting query and then apply a tag to the DeviceID shown in the results


#Replace ‘XXXXXXXXXXXXXXXXXXXX’ with the appropriate IDs relevant to your tenant/application (quotes required)





$resourceAppIdUri = ‘

$oAuthUri = “$TenantId/oauth2/token

$body = [Ordered] @{

    resource = “$resourceAppIdUri”

    client_id = “$appId”

    client_secret = “$appSecret”

    grant_type = ‘client_credentials’


$response = Invoke-RestMethod -Method Post -Uri $oAuthUri -Body $body -ErrorAction Stop

$aadToken = $response.access_token


$query = [IO.File]::ReadAllText(“c:tempQuery3.txt”); # Replace with the path to your file


$url = “

$headers = @{

    ‘Content-Type’ = ‘application/json’

    Accept = ‘application/json’

    Authorization = “Bearer $aadToken”


$body2 = ConvertTo-Json -InputObject @{ ‘Query’ = $query }

$webResponse = Invoke-WebRequest -Method Post -Uri $url -Headers $headers -Body $body2 -ErrorAction Stop

$response2 =  $webResponse | ConvertFrom-Json

$results = $response2.Results

$machine = $results.DeviceId


#Take the results from the query and parse through them to apply a tag to each DeviceID


Foreach ($machine in $machine)


#Comment sleep statement out if only planning to modify a small number of devices


Start-Sleep -Seconds 3


$url = “” +$machine+ “/tags”

$headers = @{

    ‘Content-Type’ = ‘application/json’

    Accept = ‘application/json’

    Authorization = “Bearer $aadToken”


$tag= @{

  ‘Value’ = ‘Datacenter’

  ‘Action’ = ‘Add’




$body3 = ConvertTo-Json -InputObject $tag


$webResponse = Invoke-WebRequest -Method Post -Uri $url -Headers $headers -Body $body3 -ErrorAction Stop



We have used the “add” action in this script, but you could just as easily delete tags through this method as well (assuming they haven’t been set via the registry). Simply replace ‘Add’ with ‘Remove’.

The other thing to watch out for is API limits. Due to resource constraints, we limit the amount of API calls that can be made to 100 per minute and 1500 per hour.  To avoid this, a sleep value has been applied to the script to put a pause in after each API call. Obviously, this can be removed to speed things up if the number of machines you are modifying does not hit this limit.


I have talked to you in this part of the blog about how to use scripting against the API, but there is also a great article by Tomer Brand talking about how to achieve this using Microsoft Flow (or Power Automate as it is now), where the same concepts can also be applied to Logic Apps.


We hope you’ve gotten value from this blog series on how to use tags effectively in Microsoft Defender for Endpoint. Make sure to check out Part 1 and Part 2 in the series. We welcome your feedback and questions and look forward to hearing from you.


Steve Newby (@steve_newby) and Miriam Wiesner (@miriamxyra)

Program Managers @ Microsoft Defender for Endpoint Product Group

(Credit also to Thorsten Henking for some of the API scripting input)



Brought to you by Dr. Ware, Microsoft Office 365 Silver Partner, Charleston SC.