Whats not to love about PowerShell in Azure Functions? 🙂
In this part, I will give you an overview on how I write my functions and I also added some more compute functions.

Table of Contents

  1. Function Layout
    1. Header
    2. Parameters
    3. Authentication
    4. Data and Processing
    5. Output
  2. Functions

Function Layout

The first thing is the header:

run.ps1link
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<#
.SYNOPSIS
Recieve all virtual machines in a subscription.
.DESCRIPTION
Recieve all virtual machines in a subscription.
.PARAMETER subscriptionId
Specifies the Id of the Azure Subsciption you wnat to recieve all virtual machines from.
Mandatory
.PARAMETER resourceGroup
Specifies the name of the Resource Group within the Azure subscription you wnat to recieve all virtual machines from.
Optional
.EXAMPLE
Invoke-RestMethod -Method Get -Uri 'https://<functionName>.azurewebsites.net/api/GetVms?subscriptionId=[subscriptionId]&code=[token]'
#>

Each function, script, module, etc. you write should have a header, regardless if you share it or not. When you come back after a some time, you’ll appreciate it, because you don’t need to read the entire thing again in order to understand it.

Parameters

The next part is the parameters/using part. Here you define, which namespaces and classes are used, as well as the variables that are handed over to your function.

run.ps1link
16
17
18
using namespace System.Net

param($Request, $TriggerMetadata)

The using statement makes it easy to specify which namespaces are used in the session. If you want to lean more about it, check out the about_using section of the PowerShell documentation.

The param section depends on the function trigger, in this case I use an http trigger and this comes by default with two variables: $Request and $TriggerMetadata.
$Request contains all relevant information that are passed to the function. In our case, we are espcially intrested in the Query and Body sections because they contain the values that we pass along. You can change the name of the request-variable in the “integrate” portion of each function, in case you want to.

All values you want to pass to the function as a parameter in the uri will be available in the Query portion.

1
$response = Invoke-RestMethod -Method Get -Uri 'https://<functionName>.azurewebsites.net/api/GetVms?subscriptionId=[subscriptionId]&code=[token]'
1
2
3
4
"Query": {
"code": "[token]",
"subscriptionId": "26ed4ced-d9e5-4411-be00-99c84fce635b"
}

The same goes for the body.

You can easyly access the values within the function:

1
$subscriptionId = $Request.Query.subscriptionId
1
$subscriptionId = $Request.Body.subscriptionId

$TriggerMetadata also contains all meta information of the request variable of the HTTP trigger and also adds information about the function runtime. This comes in handy during debugging.

Currently there is no support for parameters from route templates in PowerShell. If you need to use route template, you have to parse the origin url or use Azure function proxies as a workaround.

Authentication

The Authentication section acquires the access token using the secret of the managed identity of the Function App and builds the bearer token that is used later on to access the Azure APIs.
It can also be used to access the Azure graph or the Azure key vault APIs.

run.ps1link
20
21
22
23
24
$apiVersion = '2017-09-01'
$resourceURI = 'https://management.azure.com/'
$tokenAuthURI = $env:MSI_ENDPOINT + "?resource=$resourceURI&api-version=$apiVersion"
$tokenResponse = Invoke-RestMethod -Method Get -Headers @{"Secret" = "$env:MSI_SECRET" } -Uri $tokenAuthURI
$authHeader = @{Authorization = "Bearer $($tokenResponse.access_token)" }

Depending on what resource you want to access, the $resourceUri may differ.

Data and Processing

The next part actually retrieves/sets the data we want to get/set using PowerShell splatting.

run.ps1link
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
$param = @{
'Uri' = $uri
'Method' = 'Get'
'Header' = $authHeader
'ErrorAction' = 'Stop'
'ContentType' = 'application/json'
}

try {
$response = Invoke-RestMethod @param
$status = 200
} catch {
$status = 500
$response = @{
'value' = $_.Exception.Message
}
}

I like to use splatting to pass the parameters to a cmdlet, it just looks cleaner and is much easier to maintain. The values in the $param hashtable differ for each function.
Depending on the uri to call, I adjust the response codes to meet the REST requirements.

Output

Azure Functions v2 makes it pretty easy to output data and to set response codes.

run.ps1link
50
51
52
53
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = $status
Body = (Convertto-json -inputObject $($response.Value) -depth 10 -compress)
})

The Push-OutputBinding cmdlet lets you set the response body as well as the response code by using a custom type called HttpResponseContext to represent http response data.

If you can avoid using the pipeline, don’t use it! It will make your function faster!

Functions

I recently added some very basic compute functions to interact with virtual machines in Azure.
You’ll find them in the compute section of this GitHub repo.

  • StartVm
  • StopVm
  • RestartVm
  • DeallocateVm

I will add more and explain some of them in detail in a later blog post.

Stay tuned for the next part, in which I will give an example of how to use functions a real life, micro-service scenario.