Tip: avoid Wait-Debugger gotcha on Azure Functions

My biggest gotcha with Azure Functions is that you need to put Wait-Debugger in your script for local debugging, and it’s easy to forget to remove it when you deploy to Azure.

My last post talked about exploring Azure Functions’ environment, and I mentioned that you could compare the cloud version with its locally-run approximation.

Well, when you’re running your function locally, the variable $env:AZURE_FUNCTIONS_ENVIRONMENT is set to Development.

This means you can ensure that you never leave a function hanging at Wait-Debugger in the cloud by wrapping it like this:

if ($env:AZURE_FUNCTIONS_ENVIRONMENT -eq 'Development') {
    Wait-Debugger
}

Another solution is to wrap your debug command like this:

if ($Request.Query.Debug -eq 'True') {
    Wait-Debugger
}

And then invoke your function with &Debug=True when you want to debug it.

How do you handle this problem?

How to make your free Azure Linux VM actually free

Azure gives you a good amount of stuff free for 12 months when you sign up.

Quite tantalizing among these is a free Linux VM:

But if you make a B1S VM with the Ubuntu Server 18.04 LTS image, you start getting charged a trickle of cash for the disk. I amassed a bill of $1.26 before I noticed – quite shocking!

What’s up?

It turns out the 6 in P6 represents the size of the disk: 64 GB.

And the Ubuntu disk is only 30 GB. So you’re being charged for using too small a disk!

Luckily the fix is simple.

Start by creating your VM as normal:

Once it’s been provisioned, Stop (Deallocate) the VM:

Then open your VM in the Azure portal and navigate to Disks -> click disk name -> Configuration.

Set Size (GiB) to 64 and click Save.

Then start your VM back up. It should now be free of charge – and you’ll have a bit more space to play with.

Explore Azure Function’s PowerShell environment

Want to know more about the environment that your Azure Functions script is running in?

Here’s a little script I put together for this month’s Minneapolis PowerShell User Group:

# d_ExploreAzureEnvironment

# Script to explore the Azure Functions PowerShell environment
# by running commands from a menu and returning their output
# as a string.

using namespace System.Net

param($Request, $TriggerMetadata)

$itemToRun = $Request.Query.Run

$runResult = switch ($itemToRun) {
    0 { Get-ChildItem env: }
    1 { $PSVersionTable }
    2 { Get-Variable }
    3 { Get-Process }
}
if ($runResult) {
    $status = [HttpStatusCode]::OK
    $body   = $runResult | Out-String
}
else {
    $status = [HttpStatusCode]::BadRequest
    $body   = 'Supply a parameter of Run with a value between 0 and 3'
}

Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = $status
    Body       = $body
})

(code is also on GitHub)

As you can see, the script contains a menu of commands that you can select by supplying a parameter of Run with a value between 0 and 3.

The selected command is executed, its output is stored in $runResult, and $runResult is converted to a string, then returned in the HTTP response body.

You can control the whole thing in your web browser like so:

I’ve included a few commands to examine system and PowerShell variables and processes. Adding a command is as simple as this:

You can also use this script to compare the local debug environment provided by Azure Functions Core Tools with Microsoft’s hosted version (a bit more on this soon…)

It would be trivial to extend this concept and make a script that executes arbitrary commands. But it feels like a bad idea, so I restrained myself.

What other commands would you like to try out? How’s your exploration of Azure Functions going? The race to be first commenter continues!

PowerShell Azure Functions to PowerApps “Hello World” (Part 3)

In the previous two parts, we published a simple PowerShell Azure Function to the cloud and created a PowerApps Custom Connector for it.

Now – the fruits of our labour – Hello World!

PowerShell Azure Functions to PowerApps “Hello World” (Part 2)

Last time, we deployed a function to Azure.

We now have a PowerShell script sitting in the cloud which we can talk to via a HTTP REST call.

This time, we’ll create a Custom Connector in PowerApps so that we can hook our script into an app.

Part 2: Create a Custom Connector

You should first make sure that you can talk to your function with PowerShell:

  1. Open your Function in the Azure console and click Get function URL.
  2. Leave default (Function key) selected and copy the URL. You should get something like this:
    https://dan-function.azurewebsites.net/api/a_HelloWorld?code=PA1Twlk/anVrchlbKSZSvZcWQCawE5MjY2JcQ3s0/kMYqpnvI2WEMA==
  3. Append &Name=myName to the end and run with Invoke-RestMethod:
Invoke-RestMethod "https://dan-function.azurewebsites.net/api/a_HelloWorld?code=PA1Twlk/anVrchlbKSZSvZcWQCawE5MjY2JcQ3s0/kMYqpnvI2WEMA==&Name=Dan"

Once you’re happy that your function is working, switch over to Power Apps.

Here’s a video demo:

And here are step-by-step instructions:

Start with Custom Connectors → New custom connector → Create from blank

(Create from Azure Service (Preview) doesn’t work with the Azure Functions 2.x runtime – a to-be-expected example of two preview features not working together.)

  1. General screen
    Host is your Azure Functions domain, in my case:
    dan-function.azurewebsites.net
  2. Security
    Authentication type: API key
    Parameter code: code
    Parameter label: code
    Parameter location: Query
  3. Definition
    Action New action
    1. General
      Summary and Operation ID: hello_world
    2. Request
      click Import from sample
      Verb = POST
      URL = an example of a full query, including Name=myName
      Click Import, then delete the block named code, as it is already handled in the Security section.
    3. Response
      Click Add default response, then run a chunk of PowerShell like this to get an example response that you can paste into the Body field:
$response = Invoke-WebRequest "https://dan-function.azurewebsites.net/api/a_HelloWorld?code=PA1Twlk/anVrchlbKSZSvZcWQCawE5MjY2JcQ3s0/kMYqpnvI2WEMA==&Name=Dan"
# Show response in console
$response
# Copy response body to clipboard
$response.Content | clip

Now save your connector and go to the Test tab.

Under Connections, click New connection. Enter your function key when prompted (the long bunch of characters that appear after code= in a request URL).

When your connection has been created, return to the Test screen, and try out your function. You should hopefully see a familiar and reassuring block of JSON – greetings!

That’s it for now. Next time, we complete the package by adding our PowerShell function to a real life actual PowerApp.