Figure out the Parameters! Calling Azure REST APIs via Powershell Commandlets


In this post we’ll walk through the process on determining the needed parameters for the Azure Powershell Commandlet wrappers for the Azure REST APIs.  It’s sometimes tricky!  This is especially helpful if you can’t call the Rest API directly – when we’re running an Azure Powershell script in VSTS Build & Release tasks for example.  If you don’t know what we’re talking about – take a look at the last post located here to get started:  https://blogs.msdn.microsoft.com/peterhauge/2016/07/07/calling-azure-rest-apis-from-vsts-buildrelease-tasks/ .

We call call the Azure Rest APIs from the prior post, but what about all the parameters?  How do I figure that out?

Example Azure REST API

We will use the DevTest Labs Rest API as an example for the rest of this post.  The specific Azure REST API is used to create custom image of an existing Virtual Machine in a Dev/Test Lab.

image

Step 1:  Understand the REST API

The first place to look when you’re learning about the Azure REST APIs is the documentation!  You can find it here:

Azure REST API Docshttps://msdn.microsoft.com/en-us/library/azure/mt420159.aspx

This contains the main MSDN documentation for almost all the Azure Services and Resource Providers.  For example, if you needed a list of all the Virtual Machines within a resource group, you can find that by navigating this way:  “Azure Reference” –> “Virtual Machines REST” –> “List VMs in a resource group” to get the documentation.

image

If I don’t find what I need in the Azure REST API Docs, my next stop is the Azure Resource Explorer site! 

Azure Resource Explorer sitehttps://resources.azure.com

This new site is great – it contains a TON of information about resources in your existing Azure subscription.  To find more information about the Dev/Test Labs Azure REST APIs, I expand my “Subscriptions” node, then “Resource Groups” and find the resource group that contains the lab.  You can explore the site to find all the ways you can interact with the resources!  In my case I created a Dev/Test Lab in the Azure Portal (https://portal.azure.com) and then found the resource on the Azure Resource Explorer site to get the documentation.

image

In my case (find a specific Dev/Test Labs REST API call), I still don’t have all the information I need to construct the REST API call correctly.  There’s another great place to check for Azure REST APIs – the Test Drive site!

Test Drive Azure REST APIs:  https://azure.github.io/projects/apis/

We currently have a subset of APIs available on the Azure Rest API Test Drive site, but it’s a fantastic resource for the ones that are listed!  I picked “Dev Test Labs – 2016-05-15” in the dropdown and found all the Dev/Test Labs REST APIs!

image

For my example (Create a Custom Image based on an existing Virtual Machine in the Dev/Test Lab, the REST API looks like the screenshot at the top of the post.  The key pieces of information I’ll need to call the API are these:  SubscriptionId, ResourceGroupName, LabName, CustomImageName, and the SourceVMId.

For reference, here is the REST API call URL:  /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DevTestLab/labs/{labName}/customimages/{name}

Step 2:  Convert Rest API call to Azure Commandlet Parameters

Now that we know the Azure REST API to call, we need to ‘translate’ that to the Azure Commandlet to call.  Since we need a “PUT” HTTP action we will need either “New-AzureRMResource” or “Set-AzureRMResource” Azure Commandlet.  Since I’m creating a new object (Custom Image) I started with the “New-*” commandlet.  You can get more info in the last blog post for how these map:  https://blogs.msdn.microsoft.com/peterhauge/2016/07/07/calling-azure-rest-apis-from-vsts-buildrelease-tasks/ .

We find the documentation for New-AzureRMResource in the MSDN documentation here:  https://msdn.microsoft.com/en-us/library/mt652510.aspx which shows we will need the following parameters:  Location, ResourceGroupName, PropertiesObject, ResourceName, ResourceType, ApiVersion .

  • ResourceGroupName:  Since we’re calling the REST API for the Dev/Test Lab, we need to provide the resource group that contains the lab.  We will pass this into the script as a parameter
  • Location:  This is the location of the resource we’re trying to affect (the Dev Test Lab).  We can query Azure for this information in the script.
  • PropertiesObject:  We need to pass a JSON object to the REST API which has additional configuration/settings/etc., that’s needed for the call and doesn’t belong on the URL string.  In our case, we need to specify if we’re creating a Custom Image from an existing VM or VHD, the type of operating system and whether it’s generalized.  We’ll construct this in the script.
  • ApiVersion:  This one is easy, we can lift that from the Test Drive site, for Dev/Test Labs 2016-05-15 is the latest API version.
  • ResourceType:  This is one of the trickier variables to get right.  If you look at the REST API URL above, we need to take the section after “providers” like this:  “Microsoft.DevTestLab/labs”.  This is the specific resource provider, but we need a ‘nested’ resource from this provider called “customimages”.  It’s similar nesting to how the Azure SQL provider has “Server” and nested “Databases”.  So to get the full resource type we construct it this way, “Microsoft.DevTestLab/labs/customimages”
  • ResourceName:  This is name of the new custom image.  Again the custom image we want to create is within a particular DevTest Lab, so we need to use similar syntax to help the commandlet locate the resource.  In particular, “{DevTestLabName}/{NewCustomImageName}”

Now we have everything we need to construct the Azure Powershell script!  I’ve also included extra parameters to help craft the ‘Properties’ object around the type of Operating System and whether it’s Generalized/Deprovisioned.  The best place to learn more about the acceptable values for the Properties object is to look at the Linux DTL ARM Template example, or the Windows DTL ARM Template example!

param
(

    [Parameter(Mandatory=$true, HelpMessage="The name of the DevTest Lab")]
    [string] $DevTestLabName,

    [Parameter(Mandatory=$true, HelpMessage="The name of the Resource Group that holds the DevTest Lab")]
    [string] $ResourceGroupName,

    [Parameter(Mandatory=$true, HelpMessage="The Source Virtual Machine in the DevTest Lab for creating a custom image")]
    [string] $VirtualMachineName,

    [Parameter(Mandatory=$true, HelpMessage="The name of the new custom image to create in the lab")]
    [string] $CustomImageName,

    [Parameter(Mandatory=$true, HelpMessage="'Windows' or 'Linux'")]
    [string] $OsType,

    [Parameter(Mandatory=$false, HelpMessage="Use -Generalized if the Virtual Machine is generalized already")]
    [switch] $Generalized
    
)

# Get a pointer to the Virtual Machine in the DevTest Lab
$currentVm = Get-AzureRmResource `
                -ResourceGroupName $ResourceGroupName `
                -ResourceType Microsoft.DevTestLab/labs/virtualmachines `
                -ResourceName ($DevTestLabName + "/" + $VirtualMachineName) `
                -ApiVersion 2016-05-15

# Setup parameters for the Rest API call
$resourcetype = "Microsoft.DevTestLab/labs/customimages";
$resourceName = $DevTestLabName + "/" + $CustomImageName;

if ($OsType -eq 'Linux') {
    if ($Generalized.IsPresent) {
        $OsPropertiesObj = @{
            sourceVmId = $currentVm.ResourceId
            linuxOsInfo = @{
                linuxOsState = "DeprovisionApplied"
            }
        }
    }
    else {
        $OsPropertiesObj = @{
            sourceVmId = $currentVm.ResourceId
            linuxOsInfo = @{
                linuxOsState = "NonDeprovisioned"
            }
        }
    }
}
elseif ($OsType -eq 'Windows') {
    if ($Generalized.IsPresent) {
        $OsPropertiesObj = @{
            sourceVmId = $currentVm.ResourceId
            windowsOsInfo = @{
                windowsOsState = "SysprepApplied"
            }
        }
    }
    else {
        $OsPropertiesObj = @{
            sourceVmId = $currentVm.ResourceId
            windowsOsInfo = @{
                windowsOsState = "NonSysprepped"
            }
        }
    }
}
else {
    Write-Error "Invalid parameters, -OsType must be either 'Windows' or 'Linux'"
    return
}

$PropertiesObject = @{
	vm = $OsPropertiesObj
    description = $currentVm.Properties.Notes
    author = "Custom Powershell Script"
}

# Call the Rest API to create a custom image, this is a synchronous call, we have the result once it's complete
$RestAPIresult = New-AzureRmResource `
                    -Location $currentVm.Location `
                    -ResourceGroupName $ResourceGroupName `
                    -Properties $PropertiesObject `
                    -ResourceType $resourcetype `
                    -ResourceName $resourcename `
                    -ApiVersion 2016-05-15 `
                    -Force

# Let's check to see what happened and log the result
if ($RestAPIresult.Properties.ProvisioningState -eq "Succeeded") {
    Write-Host ("Successfully saved custom image of Virtual Machine: " + $currentVm.Name)
}
else {
    Write-Error ("Error snapping image for Virtual Machine: " + $currentVm.Name)
}

If you have any questions, comments or suggestions please drop them in a comment box below, thanks!

Comments (0)

Skip to main content