Q. I want to communicate to Azure using REST APIs from PowerShell. How can I do this?

A. Azure interacts primarily through RESTful APIs. Even behind the scenes the Azure PowerShell libraries call the Azure REST APIs. Many times from PowerShell you would just use the Azure PowerShell cmdlets, however there may be times that either there is no cmdlet available as the REST API is very new or perhaps you wish to interact without requiring the Azure PowerShell modules to be installed.

If you are using certificates to control access to Azure then you need a management certificate available through your PowerShell session. If you have use Import-AzurePublishSettingsFile in your session (which means you have the Azure cmdlets installed) you can try the following:

                              
$sub = (Get-AzureSubscription -Current -ExtendedDetails)
$mgmtCertThumb = $sub.Certificate.Thumbprint
$mgmtCertThumb

If a value is output you are half way there already and can use the certificate that is used as part of your PowerShell session. If however you typically use Azure Resource Manager and the Add-AzureAccount cmdlet to authenticate to Azure you will not have a certificate. The simplest method is to therefore create a management certificate, upload to Azure (I walk through this in FAQ http://windowsitpro.com/system-center/q-how-do-i-create-certificate-enable-system-center-app-controller-manage-windows-azure however you may also want to set a friendly name which matches the name of the Azure subscription which is walked through at http://blogs.technet.com/b/pki/archive/2008/12/12/defining-the-friendly-name-certificate-property.aspx) and then import the private key (the pfx file) into your local user profile (double click the PFX file and select your user account to import to). You can then fetch and use that certificate, for example to fetch by the subject name:

                              
$certName = 'CN=AzureMng2' #Subject name of the certificate
$subcert = (Get-ChildItem Cert:\CurrentUser\My | ?{$_.Subject -match "^$certName"}) #fetch the certificate from users certificate store
$mgmtCertThumb = $subcert.Thumbprint #store the thumbprint

If however your certificate has a friendly name that matches the Azure subscription name you could instead use:

                              
$sub = (Get-AzureSubscription -Current -ExtendedDetails) #if have connected to Azure subscription already
$subname = $sub.SubscriptionName
#or if you need to get the subscription
$subname = "AzureSubscriptionNameHere"
$sub = Get-AzureSubscription $subname

$subID = $sub.SubscriptionId
$subcert = (Get-ChildItem Cert:\CurrentUser\My | ?{$_.FriendlyName -match "^$subname"}) #fetch the certificate from users certificate store
$mgmtCertThumb = $subcert.Thumbprint #store the thumbprint

All of this, so far, is to arrange a certificate to authenticate to Azure. Now that you have the certificate, you create a header and body for the REST API then call it via Invoke-RestMethod. For example the code below fetches all the co-administrators for an Azure subscription based on fetching the certificate from the users certificates.

                              
$sub = (Get-AzureSubscription -Current -ExtendedDetails)
$mgmtCertThumb = $sub.Certificate.Thumbprint
$certName = 'CN=AzureMng2'

# API method
$method = "GET"

# API header
$headerDate = '2014-10-01'
$headers = @{"x-ms-version"="$headerDate"}

# generate the API URI
$subID = $sub.SubscriptionId
$URI = "https://management.core.windows.net/$subID/principals"

# grab the Azure management certificate
$subcert = (Get-ChildItem Cert:\CurrentUser\My | ?{$_.Subject -match "^$certName"})
$mgmtCertThumb = $subcert.Thumbprint

# execute the Azure REST API
$list = Invoke-RestMethod -Uri $URI -Method $method -Headers $headers -CertificateThumbprint $mgmtCertThumb
foreach( $Principal in $list.Principals.Principal)
{
    if($principal.Role -eq "CoAdministrator"){
        Write-Host $Principal.Email
    }
}

If you are performing more complex REST API calls then you will need a body element, for example changing a disk size. Notice in the example below you will also see the header contains the size of the body created which means the header definition comes after the definition of the body which uses the URI of the Update Disk REST API (defined at https://msdn.microsoft.com/en-us/library/azure/jj157205.aspx).

                              
# API method
$method = "PUT"

# generate the API URI
$sub = (Get-AzureSubscription -Current -ExtendedDetails)
$subname = $sub.SubscriptionName
$subID = $sub.SubscriptionId
$certName = 'CN=AzureMng2'
$subcert = (Get-ChildItem Cert:\CurrentUser\My | ?{$_.Subject -match "^$certName"})
$mgmtCertThumb = $subcert.Thumbprint

$diskName = "win2k3"
$newSize = 1023
$URI = "https://management.core.windows.net/$subID/services/disks/$diskName"

# create Request Body
$body = '<Disk xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Label>'+$diskName+'</Label><Name>'+$diskName+'</Name><ResizedSizeInGB>'+$newSize+'</ResizedSizeInGB></Disk>'

# API header
$headerDate = '2014-10-01'
$headers = @{"x-ms-version"="$headerDate"; "Content-Length"=$body.Length};

# execute the Azure REST API
Invoke-RestMethod -Uri $URI -Method $method -Headers $headers -CertificateThumbprint $mgmtCertThumb -Body $body -contenttype "application/xml"

If you want to use Azure AD Authentication instead there is a great blog at http://blogs.technet.com/b/keithmayer/archive/2014/12/30/authenticating-to-the-azure-service-management-rest-api-using-azure-active-directory-via-powershell-list-azure-administrators.aspx which has an example. Below is the same dump of the co-administrators using AD Authentication instead of a certificate. Note that the Azure AD Tenant used must be the owning tenant for the Azure subscription. Look at a connection to Azure management portal after logging in and selecting the right subscription. The URL shows the owning tenant for the subscription, e.g. https://manage.windowsazure.com/@savilltech.net shows me that my Azure AD tenant would be savilltech.net. Yours is likely something.onmicrosoft.com. If the Azure AD tenant does not match you will get an error when invoking the REST method related to a security token exception for the received JWT (JSON Web Token).

                              
# Load ADAL Assemblies
$adal = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll"
[System.Reflection.Assembly]::LoadFrom($adal)
[System.Reflection.Assembly]::LoadFrom($adalforms)

# Set Azure AD Tenant name
$adTenant = "yourtenant.onmicrosoft.com"
# Set well-known client ID for AzurePowerShell
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
# Set redirect URI for Azure PowerShell
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
# Set Resource URI to Azure Service Management API
$resourceAppIdURI = "https://management.core.windows.net/"
# Set Authority to Azure AD Tenant
$authority = "https://login.windows.net/$adTenant"
# Create Authentication Context tied to Azure AD Tenant
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
# Acquire token
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto")

# API method
$method = "GET"
# API header
$headerDate = '2014-10-01'
$authHeader = $authResult.CreateAuthorizationHeader()
# Set HTTP request headers to include Authorization header
$headers = @{"x-ms-version"="$headerDate";"Authorization" = $authHeader}
# generate the API URI
$sub = (Get-AzureSubscription -Current -ExtendedDetails)
$subID = $sub.SubscriptionID
$URI = "https://management.core.windows.net/$subID/principals"

# execute the Azure REST API
$list = Invoke-RestMethod -Uri $URI -Method $method -Headers $headers
foreach( $Principal in $list.Principals.Principal)
{
    if($principal.Role -eq "CoAdministrator"){
        Write-Host $Principal.Email
    }
}