Automate and Deploy Microsoft Defender Advanced Threat Protection (MDATP) via PowerShell

A few days ago, I needed to on-board Azure Windows Server VMs with Microsoft Windows Defender Advanced Threat Protection, or in short, MDATP. Sometimes Azure Security Center (ASC) has issues with on-boarding VMs and deploying the MDATP agent. As a result, I wrote the following PowerShell script that will download the MDATP.cmd file from my Azure Blob container and install it locally to the VM. This script allows you to automate it for many VMs to the scope of a Resource Group.

Now there are a few assumptions here…

  1. Download the MDATP.cmd file from the Defender Security Center portal
  2. Remove the requirement for user consent for the MDATP execution
  3. Upload the modified MDATP file to an Azure Blob container
  4. Generated a SAS URI for the MDATP file

There are many examples on the Internet on how to go step #4. Maybe in time I will do another post.

To remove the requirement of the MDATP agent to execute based on user interaction/consent can be done by removing, or commenting out the following lines of code. Launch the MDATP.cmd file within Notepad, and add a “:” before each line of code from lines 9 through 19, except line 14. Should look something like this.

Now, update and run the following PowerShell code. You can validate the VM is calling back to the Defender Security Center portal or by running the MDATPClientAnalyzer on the VM.

#update resource as needed
$resourcegroup = "YOUR_RESOURCE_GROUP"
#get only Windows Server VMs
$vms = Get-AzVM -ResourceGroupName $resourcegroup | Where-Object {$_.StorageProfile.OSDisk.OSType -eq "Windows"} | Select-Object Name
foreach ($vm in $vms)
    #friendly start message to indicate which server has started
    Write-Host "Server $vm has started..."
    #create folder, do not display error if folder already exists
    New-Item -Path "C:\" -Name "MDATP" -ItemType "directory" -ErrorAction SilentlyContinue
    #download MDATP.cmd file from Storage Account with SAS URI. Execute the cmd file. Passing "Y" to continue with installation.
    Invoke-WebRequest -Uri "YOUR_URI_SAS" -OutFile WindowsDefenderATPLocalOnboardingScript.cmd; Start-Process -FilePath "C:\MDATP\WindowsDefenderATPLocalOnboardingScript.cmd" -Verb RunAs
    #sleep for 5 seconds
    Start-Sleep -Seconds 5
    Restart-Computer -ComputerName $vm
    #friendly finished message to indicate which server has completed and will now reboot
    Write-Host "Server $vm has completed, reboot initiated..."

Azure Conditional Access – Report-Only Mode

What is Conditional Access Report-Only mode?

Not too long ago, Azure Conditional Access introduced a new feature that allows Azure Active Directory administrators to test conditional access policies and its impact without actually enforcing the policy — ie. Report-Only mode.

For starters, Azure Conditional Access allows Azure Active Directory (Azure AD) administrators to enforce a specific set of conditions to be satisfied before a user (or group) can access specific resources within Azure. For example, a policy could be something simple as, ‘Enforce all users to go through MFA in order to gain access to the Azure portal“. Or, “Only users connected to the On-Premises network can gain access to the Azure portal.

Conditional Access is one of the many layers of implementing a Zero-trust network/environment. More on that in another post…

Implementing Conditional Access policies introduces a lot of challenges to end-users as sometimes it is difficult to determine the level of impact to the end-user(s). Report-Only mode allows for a Conditional Access administrators and the policy to determine the level of impact to users before actually enforcing the policy.

In the example below, I have created a Conditional Access policy with the following conditions and controls before a user can gain access to an Azure application. In this example, that application is Azure Portal.


All Guest Users, must go through MFA in order to be granted access to Azure Management Portal. — pretty simple. Let’s see how this is setup, and the effects of Report-Only mode.

To begin, navigate to the Azure Active Directory service within the Azure Portal. Some base requirements, you need to have an Azure AD P1 or P2 license, and you the administrator must have Conditional Access Administrator (Azure AD role) as a minimum.

Create a policy, and give it some name followed by providing various requirements/conditions/controls.

Next we need to specify the user/users/group that this policy will be applicable to (or not, see the Exclude function).


Next, we need to specify the application this policy will be applicable to. Here I have selected the Azure Management Portal (Microsoft Azure Management) as the Cloud app.


Next, we need to either block or grant access to the users and the application once they pass the controls. In this case, the user must go through MFA in order to gain access to the Cloud app.


Finally we will save our configuration and leave the policy as Report-Only.


Now we can navigate to the Sign-In logs, and audit and validate our policy. Again, since this is a Report-Only policy, we can see the level of impact it would have caused to our end-users.

For more on Azure AD Conditional Access, please feel free to visit the following Microsoft URL,

Get Azure Global Administrators

Recently a customer asked me to retrieve all users that have Global Administrator access to their Azure environment. The PowerShell code below will allow you to query the Azure environment against Azure Active Directory (AAD). Nothing new here or unique here, but this quick two-liner should do the trick. 😉

$role = Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq 'Company Administrator'}
Get-AzureADDirectoryRoleMember -ObjectId $role.ObjectId | Sort-Object DisplayName | Select-Object DisplayName, UserPrincipalName, ObjectId 

Hope this was helpful!

Azure Bastion – What is it?

A little late to the party but nevertheless, I wanted to quickly show what is and how to use Azure Bastion. Azure Bastion is still in “public preview” but the solution is mature enough to start implementing now. Azure Bastion reduces the risk significantly in comparison to your traditional jumpbox approach, as it forces users to authenticate over SSL/443.

So what is Azure Bastion? Azure Bastion is a fully managed service by Azure/Microsoft that allows you to RDP and/or SSH into any Azure VM. Azure Bastion allows you to connect to your Azure VMs over HTML5-based browsers and using SSL.

Key Benefits:

  • Protection against 0-Day exploits:
    • Because Bastion sits at the perimeter of your VNet, you do not need to worry about hardening each of your VMs (although you should harden everything!!) The Azure platform will protect you keeping Azure Bastion hardened and is always up-to-date.
  • No Public IP(s) required for your Azure VMs:
    • By using Bastion, you can remove PIPs from your Azure VMs and can force your users to go through the Bastion host to connect to your VMs in your Azure environment.
  • Remote Sessions over SSL:
    • Since Azure Bastion uses HTML5 modern browsers, users can RDP/SSH over SSL (443) enabling you traverse corporate firewalls securely.
  • Simplified Management of NSGs:
    • Since Bastion is fully managed PaaS service by Azure, you no longer need to apply Network Security Groups (NSGs) on your Bastion subnet.  Since Bastion connects to your VMs over a Private IP, you can configure your NSGs to allow RDP/SSH from Azure Bastion only.


Source: Microsoft,

The architecture diagram above shows use the workflow how Azure Bastion works.

  • The Bastion host is deployed within a VNet and with its own dedicated subnet
  • Users can connect with any modern HTML5 browser
  • No Public IPs on Azure VMs

Base Requirements:

Before getting setup with Azure Bastion there are some key things to know for example.

  • You must have a Virtual Network
  • The VNet must have a subnet dedicated for Bastion and its name must be “AzureBastionSubnet”
  • It is always recommended to have the subnet with a /27 CIDR. It is easy to grow your subnet as needed, much more difficult to shrink. Always start small and grow as needed.
  • No User Defined Routing (UDR) or Network Security Groups (NSG) can be applied to the subnet.


Next step, how to deploy and configure Azure Bastion. If you want to get started with Azure Bastion, you can enroll with the Public Preview here,

Azure Policy – Audit for Network UDR Changes

Azure Policy has been available for some time now, but for folks getting start with Cloud Governance, Azure Policy is a service in Azure that allows you to manage, assign, and create custom policies. These policies can be used to enforce a global set of rules or specific set of controls for a specific environments, ie. less control and governance in a “development” environment. This allows resources to stay compliant with you enterprise standards. Azure policies can enforce different rules, from Denying specific services, for example, ensuring only resources are built within a specific region, ie. resources can only be built within the Canadian regions. Conversely, rather than enforcing, policies can also be configured to Audit, where resources will be marked if they are not compliant, for example, a Storage Account is not configured with secure transfer.

Before diving into the policy itself, I want to quick go over the types of conditions that are available, and that can be used to enforce different compliance rules. The following table shows how different policy effects work with the condition evaluation for the resulting compliance state. Although you don’t see the evaluation logic in the Azure portal, the compliance state results are shown. The compliance state result is either compliant or non-compliant.

Resource StateEffectPolicy EvaluationCompliance State
ExistsDeny, Audit, Append, DeployIfNotExist, AuditIfNotExist*TrueNon-Compliant
ExistsDeny, Audit, Append, DeployIfNotExist, AuditIfNotExist*FalseCompliant
NewAudit, AuditIfNotExist*TrueNon-Compliant
NewAudit, AuditIfNotExist*FalseCompliant
  • *The Append, DeployIfNotExist, and AuditIfNotExist effects require the IF statement to be TRUE. The effects also require the existence condition to be FALSE to be non-compliant. When TRUE, the IF condition triggers evaluation of the existence condition for the related resources.


In this example today, I want to show a real world example, where a customer recently asked to monitor any changes being made to their UDRs (User Defined Routes/Routing).

The following will continuously monitor all UDRs in the environment. If any changes are made to a single UDR table, it will be audited and its changes will be tracked. Once the policy is enabled, you can see it in action by creating/modifying a UDR.

“policyRule”: {
   “if”: {
      “anyOf”: [
            “source”: “action”,
            “like”: “Microsoft.Network/routeTables/*”
   “then”: {
   “effect”: “audit”

See below for the compliance once a change has been made to a UDR. Once you drill down to the event, the user, the activity log, you can then see the exact changes that were made to the UDR.

I hope this was helpful! 

Forcefully Revoke Azure AD User Session Access – Immediately

Sometimes it is critical to revoke a user’s Azure AD session for whatever reason it may be. You can always delete the user from Azure AD, however if the user is connected via PowerShell, the user’s token may not expire for a few more minutes, or maybe hours, depending on the token TTLs settings… So what can you do? You can forcefully revoke a user’s token session by using the following PowerShell cmdlet, “Revoke-AzureADUserAllRefreshToken“. Due to Microsoft’s ever changing Azure modules, I have tested this solution within the Azure Cloud Shell, and not on a local machine with PowerShell ISE with the AZ or RM modules.

First we need to identify which user will have its access revoked. Based off of the Revoke cmdlet, you will need to specify the “ObjectID” parameter, and the user’s ObjectID can be found within the Azure AD blade as seen below:

For additional information you can view the user’s access by executing the following cmdlet, “Get-AzRoleAssignment -ObjectId <>

Once we have identified the user and its ObjectID, we first need to connect to Azure AD, this is done by running the following cmdlet, “Connect-AzureAD -TenantId <>“. With my experience you need to specify the TenantID. Once you have connected, and verified your device, you can now run the Revoke cmdlet, as seen below, the following cmdlet needs to be executed, “Revoke-AzureADUserAllRefreshToken -ObjectId <>“. The Revoke cmdlet will not provide any details if the operation was successful, however it will throw an error if something did not go right — yes, very helpful, right? 🙂

By running this Revoke cmdlet, the user has now lost all access to its Azure AD account and any active sessions, either via the Azure Portal UI, or PowerShell will be immediately revoked. 🙂

What’s an Azure Service Principal and Managed Service Identity?

One of the general recommendations I always suggest to customers and their environments it leverage Azure Managed Service Identities (or MSI) over the traditional Service Principal (SP). Of course, the question then becomes, well what is the difference? When should I use a Service Principal and when should I use a Managed Service Identity?

In short, the difference is pretty clear. However, let’s make sure we understand what a Service Principal is, and what are they intended for…

What is a Service Principal (SP)?

In Azure, and many cloud environments, Service Principals carry the most weight with regards to access to the environment. Service Principals are an identity created for the use of applications, hosted services and automated tools to access Azure resources. This access is and can be restricted by assigning roles to the service principal(s).

What is a Managed Service Identity (MSI)?

With Managed Identities, there are two types of identities, system-assigned managed identity and user-assigned managed identity.

  1. System-assigned Managed Identity: is created and enabled directly on an Azure service. When enabled, Azure will automatically create the identity for the instance within Azure AD and will ensure it is trusted by the subscription where the instance resides. After the Azure resource/instance is created, the system-assigned managed identity credentials are provisioned onto the instance. The lifecycle is also directly attached to the Azure instance/resource and cannot be shared with other resources. In other words, the managed identity is created within Azure AD when the resource is created, and similarly the managed identity is deleted from Azure AD when the associated resource is deleted.
  1. User-assigned Managed Identity: is created as a standalone Azure resource, where the managed identity is created by the Azure AD administrator. The managed identity is trusted within the subscription and can also be assigned and shared with multiple Azure resources. The lifecycle is not dependent on the Azure resource, in other words, when the Azure resource is deleted, the managed identity is not deleted until the Azure AD administrator manually deletes the identity.

With MSI’s Azure automatically rotates/rolls the credentials every 46 days, Microsoft provides a workflow diagram on how MSIs work with Azure VM’s and other various Azure resources. See the diagram below to understand the credential rotation workflow.


What is the difference?

In short, when considering to use an MSI (Managed Service Identity) or a SP (Service Principal), also consider using a MSI for the reasons below.

MSI’s, managed the creation and automatically roll over the service principal for you. This is done by Azure in the background and requires no human/customer intervention. These credentials are rotated/rolled over every 46 days, this is a default behaviour/policy.

Use an MSI when and where available. Azure continues to grow their list of MSI’s and which resources can work with MSI’s, you can find the list HERE.



For a complete overview on MSI’s please visit Microsoft’s documentation HERE.

Step-by-Step – Installing System Center Operations Manager (SCOM) 2019 on Windows Server 2019 with SQL 2017

This post I will be installing System Center Operations Manager 2019 (SCOM) RTM, Build Number 10.19.10050.

Here is some of the background information. As this post will concentrate on the installation of SCOM 2019, I am going to omit the setup and configuration of the Domain Controller, Windows Server 2019 for the SCOM Management Server. Also to note, I am using a PaaS instance of SQL 2017 (hosted on Azure), likewise the entire environment lives on Azure in an IaaS and PaaS configuration.

Service Accounts and Local Administrator:

DomainAccount Description Local Admin on…
domainSCOM_AA SCOM Action Account SCOM
domainSCOM_DA SCOM Data Access/SDK Account SCOM
domainSCOM_SQL_READ SCOM SQL Reader n/a
domainSCOM_SQL_WRITE SCOM SQL Writer n/a
domainSCOM_Admins SCOM Administrators Group SCOM
domainSQL_SA SQL Service Account n/a

Now, if you’re lazy like me, or are tired of doing this setup for environments, I have scripted the automation of these accounts. You can find that link here, Microsoft TechNet Gallery.

Let’s Begin:

Since I am hosting SQL on a dedicated server, I will install SSRS (SCOM Reporting) on that server.

Well, that’s not new… Prerequisites. Since this is a clean, vanilla Windows 2019 server, we will need to install all the necessary Web Console components, along with Report Viewer Controls (probably SQL CLR Types too..).

  • For the Report Viewer Prerequisites, go HERE.
  • Here is the PowerShell command I ran to install the necessary IIS features/roles:
Import-Module ServerManager
Add-WindowsFeature Web-Server, Web-WebServer, Web-Common-Http, Web-Default-Doc, Web-Dir-Browsing, Web-Http-Errors, Web-Static-Content, Web-Health, Web-Http-Logging, Web-Log-Libraries, Web-Request-Monitor, Web-Performance, Web-Stat-Compression, Web-Security, Web-Filtering, Web-Windows-Auth, Web-App-Dev, Web-Net-Ext45, Web-Asp-Net45, Web-ISAPI-Ext, Web-ISAPI-Filter, Web-Mgmt-Tools, Web-Mgmt-Console, Web-Mgmt-Compat, Web-Metabase, NET-Framework-45-Features, NET-Framework-45-Core, NET-Framework-45-ASPNET, NET-WCF-Services45, NET-WCF-HTTP-Activation45, NET-WCF-TCP-PortSharing45, WAS, WAS-Process-Model, WAS-Config-APIs -restart


Once the server is back online, you will need to register ASP.Net.


You will need to apply the following using Command Prompt (as Administrator)). Yes, this is a screenshot from a previous post…Forgot to capture the screenshot when running it this time..

  1. cd %WINDIR%Microsoft.NETFramework64v4.0.30319
  2. aspnet_regiis.exe -r
  4. Reboot your server…

Once the server is back online, let’s try that Prerequisites check again….

Great! Now all of Prerequisites have been met!

Provide a meaningful Management Group Name (there’s no going back after this…)

SQL Server will be where your SCOM SQL instance(s) were installed. Remember, to either disable the Windows Firewall, or open SQL TCP Ports 1433.


I recommend always keeping this off, and manually updating your SCOM infrastructure.

One quick review. Looks good. Hit Install, and get some fresh air!

A few minutes later….

Sweet! All good. I hope this helps. If you have any questions or issues, please drop me a line.

Happy 2019 SCOM’ing!


Data Deduplication in Windows Server 2019

When Windows Server 2016 was released, Data Deduplication was not available for ReFS file system, and only available for NTFS. With Windows Server 2019, data deduplication is now available for both NTFS and ReFS file systems.

Data Deduplication is a great technology that allows you to reduces your storage footprint by removing any duplicated data blocks and replacing it with metadata.

In the scenario below, I will show you how to enable Data Deduplication and tracking the ‘saving rate’ of the data deduplication.

Install-WindowsFeature FS-Data-Deduplication

This cmdlet will allow you to install the feature. In most scenarios, ie. Storage Spaces Direct, Hyper-V, this will make most sense. Also, this cmdlet would need to be executed on all nodes.

Get-Command *Dedup*

Now that we have data deduplication installed, we can now see all the of the cmdlets available.

Enable-DedupVolume -Volume "E:","F:" -UsageType HyperV

Finally, once we enable data deduplication on the volumes, we can now track the saving rate. Note, this can be done via PowerShell, or Windows Admin Center (WAC). Note, this can only be enabled on Cluster Shared Volumes (CSV).


I hope this helps, and now you can start minimizing the data deduplication within your environment.