7
votes

In Azure CLI, there is az functionapp, but no such equivalent can be found in Powershell AzureRM-library nor Az-library.

Using raw Azure resources, I've attempted something like this to create a function app on my Application Service Plan:

New-AzResource -ResourceType 'Microsoft.Web/Sites' `
    -ResourceGroupName "MyRgName" `
    -Location "westeurope" `
    -ResourceName "MyFunctionName" `
    -kind 'functionapp' `
    -Properties @{ServerFarmId="abc-123"; alwaysOn=$True;} `
    -ApiVersion '2018-11-01' `
    -Force;

It almost works, but doesn't create a 100% working Function App. Azure Portal will spit lots of errors and warnings, for example from missing Host Keys.

Alternatives:

  • ARM-templates. What to put into a template to successfully create Azure Function? I have no idea. The one generated by Azure Portal is useless.
  • Azure Portal: Not really handy approach for environment setup from Azure DevOps release pipeline, but it will create a fully working Function App.

The question is: How to create a Function App from a Powershell script?

3

3 Answers

6
votes

I am doing the exact same thing to create a dev sandbox environment.

Provisioning function apps is a gap in the Az Powershell module but it does appear to be possible.

I provisioned my function app by following the steps here https://clouddeveloper.space/2017/10/26/deploy-azure-function-using-powershell/ but changed it to use an existing app service plan instead of consumption plan.

$AppServicePlan = "abc-123"
$AppInsightsKey = "your key here"
$ResourceGroup = "MyRgName"
$Location = "westeurope"
$FunctionAppName = "MyFunctionName"
$AzFunctionAppStorageAccountName = "MyFunctionAppStorageAccountName"
$FunctionAppSettings = @{
    ServerFarmId="/subscriptions/<GUID>/resourceGroups/$ResourceGroup/providers/Microsoft.Web/serverfarms/$AppServicePlan";
    alwaysOn=$True;
}

# Provision the function app service
New-AzResource -ResourceGroupName $ResourceGroup -Location $Location -ResourceName $FunctionAppName -ResourceType "microsoft.web/sites" -Kind "functionapp" -Properties $FunctionAppSettings -Force | Out-Null

$AzFunctionAppStorageAccountKey = Get-AzStorageAccountKey -ResourceGroupName $ResourceGroup -AccountName $AzFunctionAppStorageAccountName | Where-Object { $_.KeyName -eq "Key1" } | Select-Object Value
$AzFunctionAppStorageAccountConnectionString = "DefaultEndpointsProtocol=https;AccountName=$AzFunctionAppStorageAccountName;AccountKey=$($AzFunctionAppStorageAccountKey.Value)"
$AzFunctionAppSettings = @{
    APPINSIGHTS_INSTRUMENTATIONKEY = $AppInsightsKey;
    AzureWebJobsDashboard = $AzFunctionAppStorageAccountConnectionString;
    AzureWebJobsStorage = $AzFunctionAppStorageAccountConnectionString;
    FUNCTIONS_EXTENSION_VERSION = "~2";
    FUNCTIONS_WORKER_RUNTIME = "dotnet";
}

# Set the correct application settings on the function app
Set-AzWebApp -Name $FunctionAppName -ResourceGroupName $ResourceGroup -AppSettings $AzFunctionAppSettings | Out-Null
4
votes

This might help: To create an Azure Function we have dependency over "Storage Account", "Service Plan", "a resource group" and "Application Insight"(optional). Below i am initially defining variables. Post that i am checking if Resource group exist. If not it will create a new one. Post which i created Azure Storage Account, Service Plan and Application Insight. In Azure function we need to select Runtime Stack which can be "Java"/"DotNet"/"Python" etc. Here I am using "Dotnet". Azure Function requires Storage Account keys to link the same, which is extracted below under variables "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" etc. To link AppInsight with Function we need to map Application_Insight_InstrumentationKey. Please follow inline comments :

#=============Defining All Variables=========
$location = 'Southeast Asia'
$resourceGroupName = 'functionrgnew1'
$storageAccount = 'functionsasdnewqq1'
$subscriptionId = '<id>'
$functionAppName = 'functionapppsdfsdnew1'
$appInsightsName = 'appinsightnameprdad' 
$appServicePlanName = 'functionappplan'
$tier = 'Premium'

#========Creating Azure Resource Group========
$resourceGroup = Get-AzResourceGroup | Where-Object { $_.ResourceGroupName -eq $resourceGroupName }
if ($resourceGroup -eq $null)
{
  New-AzResourceGroup -Name $resourceGroupName -Location $location -force
}

#selecting default azure subscription by name
Select-AzSubscription -SubscriptionID $subscriptionId
Set-AzContext $subscriptionId

#========Creating Azure Storage Account========
if(!(Test-AzureName -Storage $storageAccount))
{
  New-AzStorageAccount -ResourceGroupName $resourceGroupName -AccountName $storageAccount -Location $location -SkuName "Standard_LRS"
}

#========Creating App Service Plan============
New-AzAppServicePlan -ResourceGroupName $resourceGroupName -Name $appServicePlanName -Location $location -Tier $tier
$functionAppSettings = @{
    ServerFarmId="/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Web/serverfarms/$appServicePlanName";
    alwaysOn=$True;
}

#========Creating Azure Function========
$functionAppResource = Get-AzResource | Where-Object { $_.ResourceName -eq $functionAppName -And $_.ResourceType -eq "Microsoft.Web/Sites" }
if ($functionAppResource -eq $null)
{
  New-AzResource -ResourceType 'Microsoft.Web/Sites' -ResourceName $functionAppName -kind 'functionapp' -Location $location -ResourceGroupName $resourceGroupName -Properties $functionAppSettings -force
}

#========Creating AppInsight Resource========
New-AzApplicationInsights -ResourceGroupName $resourceGroupName -Name $appInsightsName -Location $location
$resource = Get-AzResource -Name $appInsightsName -ResourceType "Microsoft.Insights/components"
$details = Get-AzResource -ResourceId $resource.ResourceId
$appInsightsKey = $details.Properties.InstrumentationKey

#========Retrieving Keys========
$keys = Get-AzStorageAccountKey -ResourceGroupName $resourceGroupName -AccountName $storageAccount
$accountKey = $keys | Where-Object { $_.KeyName -eq 'Key1' } | Select-Object -ExpandProperty Value
$storageAccountConnectionString = 'DefaultEndpointsProtocol=https;AccountName='+$storageAccount+';AccountKey='+$accountKey

#========Defining Azure Function Settings========
$AppSettings =@{}
$AppSettings =@{'APPINSIGHTS_INSTRUMENTATIONKEY' = $appInsightsKey;
                'AzureWebJobsDashboard' = $storageAccountConnectionString;
                'AzureWebJobsStorage' = $storageAccountConnectionString;
                'FUNCTIONS_EXTENSION_VERSION' = '~2';
                'FUNCTIONS_WORKER_RUNTIME' = 'dotnet';
                'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' = $storageAccountConnectionString;
                'WEBSITE_CONTENTSHARE' = $storageAccount;}
Set-AzWebApp -Name $functionAppName -ResourceGroupName $resourceGroupName -AppSettings $AppSettings
-2
votes

The best way to do this from PowerShell is to use an ARM template, rather than try to create each resource individually. You can find an example template here. It also hooks up the app to github, but you can leave out that part if you just want an empty app