Create an Azure VM with Azure REST API with PowerShell

I like to work with REST APIs in the past, so I decided to head over to the Azure REST API and create an Azure VM with Powershell and Azure Rest API. I thought I would do it in a quick session between two appointments but failed miserably. It took me a few hours to figure out how to deal with Azure REST API, especially with the correct JSON, to provide the Image I need.

So, this is a walk-through post because some steps need to be prepared.

In the end, you will get a PowerShell Script which will create an Azure VM using Azure REST API without any Credentials Prompts. We need an Azure App Registration and assign the correct Roles, Ressource Group, existing NEtwork Interface, and other Properties to achieve this.

I have written a GRAPH API Series, where i explained how to create an Azure App Registration, so if there is something not clear, read that: MS Graph API

Azure App Regsitration for Azure REST API

Of course, we want to have a Script that will run without user interaction, so we need to create an Azure App Registration for this.

So let’s create an Azure App Regsitration and note the Application and Tenant ID because we need that for our Script.

Also, create a Client Secret and copy that Secret to use it for the PowerShell Script.

Use those Values in the Script at that Place

Now let’s assign a Role to that App Registration and remember the Name you gave your App.

Navigate to your Subscription, where the VM is created, and navigate to “Access control (IAM).”

Click “Add” and “Add role assignment.”

As Role select “Contributor” and enter the App Name in “Select” and choose the App

Click “Save” to make sure the App has the Role assigned.

As we are right now in the Subscription Section, navigate back to “Overview,” and note the Subscription ID for the PowerShell Script

and enter that ID to the PowerShell Script.

Script Variables

Now let’s go through our Variables in the Script and how to use them.

VM Details

Those three should be easy. Make sure the RessourceGroup and NetworkInterface exist.

The VMName can be anything and will be created during the Script.


Location

Location Value can be a little tricky to get the correct value.

The Easiest Way to get a list with all Locations in your Subscription, run the following CMDlet from the AZ Module

Get-AzLocation

that will result in a list of Locations

To help, here is a Table from 18.08.2021; use the “Location” Value for the Script.

LocationDisplayNameProviders
eastasiaEast AsiaSystem.Collections.Generic.List`1[System.String]
southeastasiaSoutheast AsiaSystem.Collections.Generic.List`1[System.String]
centralusCentral USSystem.Collections.Generic.List`1[System.String]
eastusEast USSystem.Collections.Generic.List`1[System.String]
eastus2East US 2System.Collections.Generic.List`1[System.String]
westusWest USSystem.Collections.Generic.List`1[System.String]
northcentralusNorth Central USSystem.Collections.Generic.List`1[System.String]
southcentralusSouth Central USSystem.Collections.Generic.List`1[System.String]
northeuropeNorth EuropeSystem.Collections.Generic.List`1[System.String]
westeuropeWest EuropeSystem.Collections.Generic.List`1[System.String]
japanwestJapan WestSystem.Collections.Generic.List`1[System.String]
japaneastJapan EastSystem.Collections.Generic.List`1[System.String]
brazilsouthBrazil SouthSystem.Collections.Generic.List`1[System.String]
australiaeastAustralia EastSystem.Collections.Generic.List`1[System.String]
australiasoutheastAustralia SoutheastSystem.Collections.Generic.List`1[System.String]
southindiaSouth IndiaSystem.Collections.Generic.List`1[System.String]
centralindiaCentral IndiaSystem.Collections.Generic.List`1[System.String]
westindiaWest IndiaSystem.Collections.Generic.List`1[System.String]
canadacentralCanada CentralSystem.Collections.Generic.List`1[System.String]
canadaeastCanada EastSystem.Collections.Generic.List`1[System.String]
uksouthUK SouthSystem.Collections.Generic.List`1[System.String]
ukwestUK WestSystem.Collections.Generic.List`1[System.String]
westcentralusWest Central USSystem.Collections.Generic.List`1[System.String]
westus2West US 2System.Collections.Generic.List`1[System.String]
koreacentralKorea CentralSystem.Collections.Generic.List`1[System.String]
koreasouthKorea SouthSystem.Collections.Generic.List`1[System.String]
francecentralFrance CentralSystem.Collections.Generic.List`1[System.String]
francesouthFrance SouthSystem.Collections.Generic.List`1[System.String]
australiacentralAustralia CentralSystem.Collections.Generic.List`1[System.String]
australiacentral2Australia Central 2System.Collections.Generic.List`1[System.String]
uaecentralUAE CentralSystem.Collections.Generic.List`1[System.String]
uaenorthUAE NorthSystem.Collections.Generic.List`1[System.String]
southafricanorthSouth Africa NorthSystem.Collections.Generic.List`1[System.String]
southafricawestSouth Africa WestSystem.Collections.Generic.List`1[System.String]
switzerlandnorthSwitzerland NorthSystem.Collections.Generic.List`1[System.String]
switzerlandwestSwitzerland WestSystem.Collections.Generic.List`1[System.String]
germanynorthGermany NorthSystem.Collections.Generic.List`1[System.String]
germanywestcentralGermany West CentralSystem.Collections.Generic.List`1[System.String]
norwaywestNorway WestSystem.Collections.Generic.List`1[System.String]
norwayeastNorway EastSystem.Collections.Generic.List`1[System.String]
brazilsoutheastBrazil SoutheastSystem.Collections.Generic.List`1[System.String]
westus3West US 3System.Collections.Generic.List`1[System.String]
swedencentralSweden CentralSystem.Collections.Generic.List`1[System.String]

Image Settings

Now there is the most tricky part, at least for me in that example. To Find the correct Server Image to install. In our example, I use an existing Image from the Marketplace and install the latest Server 2019.

So, how to get that Values?

Run that command to get a list of Publisher

Get-AzVMImagePublisher -Location $Location | Select PublisherName

$publisher = "MicrosoftWindowsServer"

Now, run the following to get the Offer Names

Get-AzVMImageOffer -Location $Location -PublisherName $publisher | select Offer

$offer = "WindowsServer"

Now its time to get the SKU with that command

Get-AzVMImageSku -Location $Location -PublisherName $publisher -Offer $offer | select SKUS


$sku = "2019-Datacenter"

You can use the “Latest” Value to get the newest Image, but you can also use one of the values below.

Get-AzVMImage -Location $Location -PublisherName $publisher -Offer $offer -Sku $sku | Select Version

The rest is now the whole Script where we connect to Azure Rest API with the Azure App Registration Details and send a JSON to create the VM.

In the end, we will wait until the Deployment is successful with a do/until the command.

The Script to create an Azure VM with PowerShell and Azure REST API


$applicationId = 'your Application ID'
$tenantId = 'your Tenant ID'
$secret = 'your Secret'

$subscriptionId = 'your Subscription ID'


#VM Details
$RessourceGroupName = "RG_TEST_TechguyNewVM"
$VMname = "TESTVM"
$NetworkInterfaceName = "TESTVM-NIC"
$vmSize="Standard_D1_v2"

#Location
$Location = "northeurope"


#Image Settings
$publisher = "MicrosoftWindowsServer"
$offer = "WindowsServer"
$sku = "2019-Datacenter"
$version = "latest"


#VM Login
$User="User"
$PW"superSa3PW!"

#API Version
$apiversion="2021-03-01"


$param = @{
  Uri    = "https://login.microsoftonline.com/$tenantId/oauth2/token?api-version=$apiversion";
  Method = 'Post';
  Body   = @{ 
    grant_type    = 'client_credentials'; 
    resource      = 'https://management.core.windows.net/'; 
    client_id     = $applicationId; 
    client_secret = $secret
  }
}

$result = Invoke-RestMethod @param
$token = $result.access_token



$headers = @{
  "Authorization" = "Bearer $($token)"
  "Content-type"  = "application/json"
}




$URL = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$RessourceGroupName/providers/Microsoft.Compute/virtualMachines/$($VMname)?api-version=$apiversion"

$bodyNewVMexistingNetwork = @"
    {
        "location": "$location",
        "properties": {
          "hardwareProfile": {
            "vmSize": "$VMsize"
          },
          "storageProfile": {
            "imageReference": {
              "sku": "$sku",
              "publisher": "$publisher",
              "version": "$version",
              "offer": "$offer"
            },
            "osDisk": {
              "caching": "ReadWrite",
              "managedDisk": {
                "storageAccountType": "Standard_LRS"
              },
              "name": "myVMosdisk",
              "createOption": "FromImage"
            }
          },
          "osProfile": {
            "adminUsername": "$User",
            "computerName": "$VMname",
            "adminPassword": "$PW"
          },
          "networkProfile": {
            "networkInterfaces": [
            {
                "id": "/subscriptions/$subscriptionId/resourceGroups/$RessourceGroupName/providers/Microsoft.Network/networkInterfaces/$NetworkInterfaceName",
                "properties": {
                  "primary": true
                }
              } 
              ]
            }
          }
        } 
      } 
    }
"@


Invoke-RestMethod -Method PUT -URI $URL -headers $headers -body $bodyNewVMexistingNetwork



### Get Status

do {
  $URLtoGet = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$RessourceGroupName/providers/Microsoft.Compute/virtualMachines/$($VMname)?api-version=$apiversion"
  $Result = Invoke-RestMethod -Method GET -URI $URLtoGet -headers $headers
  $result.properties.provisioningState
  Start-Sleep -Seconds 5
} until ($result.properties.provisioningState -ne "Creating")





##Connect-AzAccount
#Get-AzVMImagePublisher -Location $Location | Select PublisherName
#Get-AzVMImageOffer -Location $Location -PublisherName $publisher | select Offer
#Get-AzVMImageSku -Location $Location -PublisherName $publisher -Offer $offer | select SKUS
#Get-AzVMImage -Location $Location -PublisherName $publisher -Offer $offer -Sku $sku | Select Version
##
#
#Get-AzVMImage -Location $Location -PublisherName $publisher -Offer $offer -Skus $sku -Version $version

Self Service Azure VM Creation with au2mator Self Service Portal

Self Service and delegate your Azure VM creation with au2mator Self Service Portal – LINK

GitHub Repo

Here is the Azure REST API GitHub Repo with other examples: Seidlm/Microsoft-Azure Examples (github.com)

External Docs

Virtual Machines – REST API (Azure Compute) | Microsoft Docs

Michael Seidl aka Techguy
au2mate everything

Leave a Comment

Your email address will not be published. Required fields are marked *

*