-
Notifications
You must be signed in to change notification settings - Fork 54
(Insider Preview) New Programming Model
The new v2 programming model is designed to provide an idiomatic development experience for PowerShell developers. Although this new experience is yet be released (timeline TBD), you can use this document to learn more about it and test it out locally.
In accordance with user feedback, we wanted to provide a more frictionless onboarding experience for customers that would simultaneously reduce the complexity of an app's code and file structure.
To that end, the Azure Functions PowerShell team reimagined PowerShell-based Azure Functions development by flattening an app's directory structure, allowing multiple function definitions within the same file, and reducing complexity by streamlining Function definitions and removing the language-agnostic function.json files.
Note that leveraging the v2 programming model will provide an improved and seamless way to create functions, with the underlying deployment, debugging, and monitoring experience remaining the same.
- General Notes
- Supported Today
- Examples
- Get Started
-
The only files that are scanned for functions are the ones in the function app root folder. Any other files may be used to contain helper functions, but function declarations must be at the root. EXAMPLE: bug-bash-app/functions.psm1 is scanned, but bug-bash-app/src/functions.psm1 will not be
-
For the binding attributes, only named arguments are supported. Positional arguments will not work.
Comparing the v1 and v2 programming models
run.ps1
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
$body = "Hello from PowerShell v1 programming model"
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = $body
})
function.json
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
}
[Function()]
param(
[HttpTrigger()]
$Request,
$TriggerMetadata
)
$value = ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = 'New Programming Model rules! (Hero executed)'
})
$value | Push-OutputBinding -Name Response
Comparing the folder structure of v1 and v2:
The following is the folder structure for a function application containing three functions.
- .vscode
- EventGridTrigger1
- function.json
- run.ps1
- HttpTrigger1
- function.json
- run.ps1
- TimerTrigger1
- function.json
- run.ps1
- .funcignore
- .gitignore
- host.json
- local.settings.json
- profile.ps1
- requirements.psd1
- .vsode
- .funcignore
- .gitignore
- functions.ps1
- host.json
- local.settings.json
- profile.ps1
- requirements.psd1
As you can see, the folder structure of a function application using the v2 programming model is simpler and flat.
Triggers:
- HTTP
- Timer
- EventGrid
- EventHub
- Orchestration
- Activity
Output Bindings:
- HTTP
- EventHub
DurableClient is also supported!
You can also use a combination of InputBinding
, OutputBinding
, and AdditionalInformation
to construct bindings of any other type. InputBinding
and OutputBinding
should be used to specify the type of binding, and AdditionalInformation
allows you to add key-value pairs to that binding.
HTTP Trigger
using namespace System.Net
using module AzureFunctions.PowerShell.SDK
function HttpTriggerMinimal {
[Function()]
param(
[HttpTrigger()]
$Request,
$TriggerMetadata
)
$value = ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = 'New Programming Model rules! (Hero executed)'
})
$value | Push-OutputBinding -Name Response
}
function HttpTriggerMaximal {
[Function(Name='Trig')]
[HttpOutput(Name='Resp')]
param(
[HttpTrigger(AuthLevel='anonymous', Methods=('Get', 'Post'), Route='rerouted')]
$Request,
$TriggerMetadata
)
$value = ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = 'The Http trigger invocation was successful'
})
$value | Push-OutputBinding -Name Resp
}
Timer Trigger:
function TimerTriggerMinimal {
# Input bindings are passed in via param block.
param(
[TimerTrigger(Chron='0 */5 * * * *')]
$Timer
)
# Get the current universal time in the default string format
$currentUTCtime = (Get-Date).ToUniversalTime()
# The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled.
if ($Timer.IsPastDue) {
Write-Host "PowerShell timer is running late!"
}
# Write an information log with the current time.
Write-Host "PowerShell timer trigger function ran! TIME: $currentUTCtime"
}
EventGrid
function EventGridTrigger() {
[Function()]
param(
[EventGridTrigger()]
$Request,
$TriggerMetadata
)
$value = ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = 'The Http trigger invocation was successful'
})
$value | Push-OutputBinding -Name Response
}
EventHub
# NOTE: all 4 arguments are required.
function EventHubTrigger() {
[Function()]
param(
[EventHubTrigger(EventHubName='', ConsumerGroup='', Cardinality='', Connection='')]
$Request,
$TriggerMetadata
)
$value = ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = 'The Http trigger invocation was successful'
})
$value | Push-OutputBinding -Name Response
}
# HttpOutput syntax:
# [HttpOutput(Name='<name>')]
# EventHubOutput syntax:
# [EventHubOutput(Name='<binding name>', EventHubName='<event hub name>', Connection='<event hub connection>')]
Durable
function DurableFunctionsHttpStart1 {
[Function()]
param(
[DurableClient(Name='starter')]
[HttpTrigger(AuthLevel='anonymous', Methods=('get', 'post'), Route='DurableStart')]
$Request,
$TriggerMetadata
)
$FunctionName = "DurableFunctionsOrchestrator1"
$InstanceId = Start-DurableOrchestration -FunctionName $FunctionName
Write-Host "Started orchestration with ID = '$InstanceId'"
$Response = New-DurableOrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId
Push-OutputBinding -Name Response -Value $Response
}
function DurableFunctionsOrchestrator1 {
[Function()]
param(
[OrchestrationTrigger()]
$Context
)
$output = @()
$output += Invoke-DurableActivity -FunctionName 'Hello1' -Input 'Tokyo'
$output += Invoke-DurableActivity -FunctionName 'Hello1' -Input 'Seattle'
$output += Invoke-DurableActivity -FunctionName 'Hello1' -Input 'London'
$output
}
function Hello1 {
[Function()]
param(
[ActivityTrigger()]
$name
)
"Hello $name!"
}
Generic Binding Syntax Following is an HTTP trigger written in the style of the generic, but use your imagination!
function GenericTrigger() {
[Function()]
[OutputBinding(Type='http', Name='Response')]
[AdditionalInformation(BindingName='', Name='', Value='')]
param(
[InputBinding(Type='httpTrigger')]
[AdditionalInformation(BindingName='Request', Name='authLevel', Value='anonymous')]
[AdditionalInformation(BindingName='Request', Name='methods', Value=('GET', 'POST'))]
$Request,
$TriggerMetadata
)
}