Welcome back!
Last time (2025 – Automating updated Named Locations – like a boss! – -Have you patched yet?) we wanted to automate blocking malicious IP’s by importing these into a Named Location Conditional Access policy. This time we have a scenario where we want to automate blocking malicious urls/domains by importing these into Defender IOC’s with Defender API.
If you are subscribing to a blocklist from a vendor and you run AlwaysOnVPN solution and automatically import this blocklist in your firewall – you’re all god also here. But if you’re not running AlwaysOnVPN – how can you still make sure that these urls/domains are blocked from your users?
Once again I will be basing this blog heavily on a script shared by SYS-IKT – especially Endre Nordeide I don’t think this is published yet, so I will share it here.
This specific blocklist requires you to subscribe to KRIPOS blocklist to acquire the necessary API-key – but hopefully this blog also inspires those of you that doesn’t but maybe gets list from other places.
If you want to hae a read up on what Defender IOC is and how to manage them, Microsofts documentation is here; Overview of indicators in Microsoft Defender for Endpoint – Microsoft Defender for Endpoint | Microsoft Learn

Our task/to-do list will be the following;
- Create a locked down server/VM to run the scripts from (make this according to your company policy – I will not show these steps here)
- Create a non-domain-joined local user without any admin-rights – but give the user a “Log on as a batch job”-privilege on this server only
- Create the app-registration with correct privileges, scopes and secret-id/-value-authentication
- Install Microsoft Graph on the server and check that you can connect
- Create a config-file with necessary data so the script will work
- Implement the script to suit our environment
- Check that the script is working before we make the scheduled task
- Create the scheduled task
Disclaimer;
- There will be tasks you perform here that needs local admin privileges for setup – but the user performing the scheduled task does not need any admin rights.
- If you see anything done here that could be done with even more least privilege – I would be very happy if you shared and I will update the blog accordingly.
Create a non-domain-joined local user without any admin-rights – but give the user a “Run as a batch job”-privilege on this server only
Open Local Users and Groups on the server, I choose to type it because I think it has a fun name lusrmgr.msc

Give it a suitable name and description and make a choice on a password policy that suits your policy and store the pw in a password manager.
If you use a domain-user and the server is a domain joined server – feel free to use GPO to delegate “Log on as a batch job”. If you are using a local user, you can edit the local group policy like this;

Now let’s move on to making the application in Entra.
Create the app-registration with correct privileges, scopes and with client secret authentication
Last time we made certificates for authentication. This script connects through API and as of today I don’t have the skills to make the script use certs. But I think this topic is so important to get out there and share and don’t want that to be a blocker – so we will use client secrets instead to make this work. If you have any input on how to make the script work with certificates instead; please share and I will update accordingly!
For this you need to have the necessary role in Entra to create an application. Roles that have this is Global Administrator, Cloud Application Administrator, Application Administrator and Application Developer – choose what is right for your company least privilege policy.
Sign into the azure portal, locate “App registration” and choose “+ New registration” – optionally Sign in to Microsoft Entra admin center, Expand Azure Active Directory, Click on Applications > App registrations and Select New registration.
Choose a suitable name for the application and choose supported account types. In this scenario I will go for single-tenant only.

The application appears, note down the App-ID and tenant-ID – we will need this for the config-file later.
The application also requires some permissions to be able to update the DefenderIOC.
- Click on API permissions > Add a permission

- Select «APIs my organization uses»> Search for WindowsDefenderATP

- Select Application permissions
- Search for Ti.ReadWrite.All
- Click Add permissions
- Click on Grant admin consent
- Click Yes
- The status shows a green checkmark

As mentioned you could also go for the certificate option approach for login – but we will use the client-id / client-secret this time.
- Click on Certificates & secrets
- Click Client secrets
- Click on “New client secret” and give it a description and choose for how long the lifetime of the client secret should be so it suits your policies.

- The client secret/id appears in the list, make sure to store these in a safe place/password manager right away – you will not be able to retrieve the secret value at a later time!!!

Install Microsoft Graph on the server and check that you can connect
Check out Ali Tajarin’s guide on installing Microsoft Graph in detail here; https://www.alitajran.com/install-microsoft-graph-powershell/
To shorten it down, we do this;
- Run powershell in elevated prompt
- Set-ExecutionPolicy RemoteSigned -Force
- Install-Module PowershellGet -Force (It may take some time to download and install the Microsoft Graph PowerShell module. So give it a couple of minutes.)
- Install-Module Microsoft.Graph.Beta -AllowClobber -Force
Create a config-file with necessary data so the script will work
This blog is both a way to inspire you how to do this for several scenarios that suits anyone – but in this example, I will rely on the script that will automate a download of a url/domain-blocklist and automate the upload of this into the DefenderIOCs. To get this to work, you need to be a customer with KRIPOS and subscribe on the service that gives you access to this list. If you do that, you will get an API-key for access.
With all that in place, we can make a simple txt-file called config. The syntax for this file should be like this;
$blocklistname = KRIPOS
$blocklistdomain = blocklistdomain.local
$blocklistkey = xxxxxxxxxxxxxxxxxxxxxxxx
$tenantId = 12345678-abcd-1234-abcd-0123456789abcd
$AppId = 12345678-abcd-1234-abcd-0123456789abcd
$appSecret = 12345678-abcd-1234-abcd-0123456789abcd
$expirationDate = 30
$action = Block
$smtpserver = X.X.X.X
$smtpto = xxxx@yourcompany.com
$smtpfrom = xxxx@yourcompany.com
$logDays = 14 $TenantId = *yourtenant-id*

Implement the script to suit our environment
The script I use in this scenario could be found here; Powershell/Add-MSDefIOCFromKriposBlocklist.ps1 at main · prottecio/Powershell · GitHub
This script will first check the md5 of the blocklist which means that you can make the scheduled task to check this pretty often as it will only download if there is made any changes to it. It also make batch-jobs for uploading so it does not hit the API rate limit in Defender. It will also clean up logs on server and even set an expire date on the indicator meaning that if an indicator is removed from KRIPOS/HelseCERT, the indicator will be removed from your IOC-list after the days you set in the config file.
Good work Endre Nordeide!
Disclaimer – the KRIPOS LIST does not yet have a md5 hash to check for, I therefore commented out the md5 functionality aswell. (Line 84,85,211) But if you use this guide to also automatically update your DefenderIOCs from HelseCERT/KommuneCERT blocklist, they support md5 hash-check.
Check that the script is working before we make the scheduled task
Before we create our scheduled task, I will run the script and see that it;
- Downloads the blocklist and creates the md5 check
- Connects to the app with client id/secret authentication
- Imports the urls/domains to DefenderIOC’s.
You can find the indicators by logging into https://security.microsoft.com/, go to System à Settings à Endpoints à Indicators
Before;

After;

Success – added over 500 urls/domains!!!
Now we want to automate it further, making a scheduled task that does this how often we want it. In our scenario, I want it to be done every hour.

Create the scheduled task
Create a new basic task and give it a suitable name and description

Trigger;
Choose the trigger for your task. I will choose “Daily” now and afterwards edit it to be every hour.
Action;
I want it to start a program with the following options;
Program/script: powershell
Arguments; -NoProfile -ExecutionPolicy Bypass -File “C:\source\KriposBlocklist DefenderIOCs\Add-MSDefIOCFromKRIPOSBlocklist.ps1”
Start in; “C:\source…”

After saving, I edit it again, choose Edit Trigger and set the repeat task to 1 hour and also “Stop task if it runs longer than 1 hour”


Check if it all works
There is several ways to see that everything is set in motion now. You can check
- History in scheduled tasks to see that the task is really running
- Check that your indicators got populated in Defender – go to https://security.microsoft.com/ and find Settings / Endpoints / Indicators
- Check the logfiles that the script generates to see that it does what it’s supposed to do.
Secure the Service Principal with conditional access policy
As we saw in the creation of the application – this application has permissions to read and write to DefenderIOCs. Therefore, it would be a good idea to protect this a little bit. To start, I want this service principal to only be able to sign-in from our trusted location.
To do this in Conditional Access on a workload Identity/Service Principal you will need a stand-alone license. I don’t have that in my tenant so I can’t show it here – but Christian Frohn has a great write-up on how-to, if you are interested. Check it out here; Securing Service Principals in Microsoft Entra ID with Conditional Access policies – christianfrohn.dk
That’s it. We accomplished our goal, and we have now automated a workload that downloads the blocklist and uploads it into DefenderIOC – automatically. Great work!

Are you still with me?
If you follow basically the same procedure above – but instead us this script; blocklist/m365-single-tenant/Add-MSDefIOCFromHSBlocklist.ps1 at master · helsecert/blocklist · GitHub and have a subscription for HelseCERT/kommuneCERTs blocklist – you can populate your DefenderIOC’s with additional 10000+ indicators!
Until next time, stay safe, please share and please reach out if you have any questions, improvement ideas or just want to chat!