Identify Azure VMs without Antimalware Extension Installed

Securing cloud infrastructure and services plays a vital role in architecting a solution. As a solution designer or architect, it is an important task to take account of all the possible security measurements need for the solution. It can be from infrastructure to application and database

When security plays a major role in cloud security, it uses a concept called Shared Security Responsibility. In Shared Security Responsibility as a customer, we are bind to part of responsibilities as well as cloud service providers who have the responsibility of securing the resources. Customer responsibility we refer to as security in the cloud and cloud provider responsibility we refer to as security of the cloud.

Following diagram visualised the Shared Security Responsibility

Responsibility zones
Image – MS Docs

So from today’s post I’ll discuss and demo how we can identify VMs that are not installed with Azure Antimalware extension. It’s important to install Antimalware extension to any production VMs

As the first step we need to get the subscriptions, we are going to search for VMs without Antimalware extension

In the following code, snippets export the subscriptions from the tenant and save it to a CSV file.

#Get the subscriptions
Write-Host "Getting Subscription Details" -ForegroundColor "Yellow"
Get-AzSubscription | Where-Object {$PSItem.State -eq "Enabled"} | Export-Csv -Path .\subscriptions.csv

Next subscriptions are imported to an variable $subscriptions

#Import the Subscriptions
Write-Host "Importing Subscriptions" -ForegroundColor "Yellow"
$subscriptions = Import-Csv -Path .\subscriptions.csv

Next, we will go through each subscription (if available) to get the VM details. For this, we use a foreach. foreach takes each object at a time and save it to the variable $sub. In this way we can work with this single object.

foreach ($sub in $subscriptions) {}

Inside this, for each as a first step, we need to login to the subscription to get details as follows.

    #Set contexts
    Set-AzContext -Subscription $sub.Name
    $SubName = $sub.Name

Next getting all the VMs in the subscription and save to a variable $VMs

    # Getting VMs in the subscription
    Write-Host "Getting VM Details.." -ForegroundColor "Yellow"
    $VMs = Get-AzVM 

Next filter for Windows VMs using Where-Object

$WindowsVMs = $VMs | Where-Object { $PSItem.StorageProfile.ImageReference.Offer -eq "WindowsServer" }

Next, we need to check each VM for the Antimalware extension. To do that we run another foreach loop for the VMs we identified. This foreach loop takes each filtered Windows VM and execute the commands inside the block.

foreach ($VM in $WindowsVMs) {}

Next query the extension installed on each VM.

$extension = Get-AzVMExtension -ResourceGroupName $Vm.ResourceGroupName -VMName $VM.Name

Following snippet use if condition to check the Antimalware extension installed, if the condition results true, create a hash table with details and export it to CSV file. If the condition fails, create a separate hash table and append the result to the same CSV file.

        if ($extension.Name -contains "IaaSAntimalware") {
            Write-Host "IaaSAntimalware is Installed in" $VM.Name -ForegroundColor "Cyan"

            $sucesshash = @{
                VMName            = $VM.Name
                Extension         = "IaaSAntimalware"
                ProvisionedStatus = "Succeeded"
                Subscription      = $SubName

            New-Object -TypeName PSObject -Property $sucesshash | Export-Csv -Path .\AntimalwareStatus.csv -Append -NoClobber

        else {
            Write-Host "IaaSAntimalware is Not Installed in" $VM.Name -ForegroundColor "Red"

            $failhash = @{
                VMName            = $VM.Name
                Extension         = "IaaSAntimalware"
                ProvisionedStatus = "Not Installed"
                Subscription      = $SubName

            New-Object -TypeName PSObject -Property $failhash | Export-Csv -Path .\AntimalwareStatus.csv -Append -NoClobber

Following include the full script.