Deploy Azure Function, using PowerShell

One of my favourite parts of AZURE is the way you can incorporate a set of PowerShell, in a callable wrapper – or via a Timer – aka, scheduled task.

You can then call this from within a Microsoft Flow – in Office 365 – or have a timer that then awakens, and does something.

My function is simple enough – it logs in to SharePoint, and checks a document library – and then emails a combined reminder list – once a day.

Deploying is easy – when you have access to the Azure tenant – but for a SCRIPTED deployment, I had a bunch of tasks to get through :

  1. Coffee
  2. Create Azure Resource Group – ie. a bucket for all the elements
  3. Create Azure Storage Account
  4. Create Azure Function App
  5. Update some Azure Function App Settings
  6. Upload the Azure Function code (PowerShell)
  7. Upload the MODULE files also
  8. Beer

** I can’t help with step #1 (long black or “Americano”) – or #8 (Sample, or 150 Lashes) – but here’s some tips/code for the other bits.

Smile 

1. Coffee (and login)

Execute the command to connect to Azure – you get a dialog box for username/password :

2. Create Azure Resource Group

image

3. Create Azure Storage Account

image

4. Create Function App

image

5. Update Azure Function Settings

Some of these are necessary for the operation of the Azure Function – others are just CUSTOM for my use/needs – eg. connecting to Office 365 has a User/Password + URL

image

6. Upload Azure Function – from PowerShell file

The contents of the PS1 file are loaded, and the set in the “props” when adding a new Azure Resource – I’m using a timer trigger – you could also do a HTTP trigger.

image

7. Upload the MODULE files for the Azure Function

I used an updated version of the code within this blog post – to push files into the “modules” folder – which is needed for SharePoint Client / CSOM and such.

http://blog.octavie.nl/index.php/2017/03/03/copy-files-to-azure-web-app-with-powershell-and-kudu-api

I have a subfolder called “modules” – with the actual files.    (eg. C:\dev\modules)

image

8. Beer

Well, before we do that – here’s the entire script – using a heap of Azure RM PowerShell functions – you’ll need to install those, if you don’t have them.

Here’s a list of all the commands I’ve used :

  • Get-AzureRmResource
  • Get-AzureRmResourceGroup
  • Get-AzureRmStorageAccountKey
  • Get-PublishingProfileCredentials
  • Invoke-AzureRmResourceAction
  • New-AzureRmResource
  • New-AzureRmResourceGroup
  • New-AzureRmStorageAccount
  • Set-AzureRMWebApp
  • Test-AzureName

Source Code

Hope this works for you – it was a fun process to piece it all together :

$location = ‘Australia Southeast’

$resourceGroupName = ‘rgqwerty’

$storageAccount = ‘saqwerty’

$functionAppName = ‘faqwerty’

$functionName = ‘azurefunctionqwerty’

$SourceFile = ‘sourcefile.ps1’

# =========================================================================

$resourceGroup = Get-AzureRmResourceGroup | Where-Object { $_.ResourceGroupName -eq $resourceGroupName }

if ($resourceGroup -eq $null)

{

New-AzureRmResourceGroup -Name $resourceGroupName -Location $location -force

}

# =========================================================================

if (!(Test-AzureName -Storage $storageAccount))

{

New-AzureRmStorageAccount -ResourceGroupName $resourceGroupName -AccountName $storageAccount -Location $location -SkuName “Standard_LRS”

}

# =========================================================================

$functionAppResource = Get-AzureRmResource | Where-Object { $_.ResourceName -eq $functionAppName -And $_.ResourceType -eq ‘Microsoft.Web/Sites’ }

if ($functionAppResource -eq $null)

{

New-AzureRmResource -ResourceType ‘Microsoft.Web/Sites’ -ResourceName $functionAppName -kind ‘functionapp’ -Location $location -ResourceGroupName $resourceGroupName -Properties @{} -force

}

# =========================================================================

$keys = Get-AzureRmStorageAccountKey -ResourceGroupName $resourceGroupName -AccountName $storageAccount

$accountKey = $keys | Where-Object { $_.KeyName -eq “Key1” } | Select Value

$storageAccountConnectionString = ‘DefaultEndpointsProtocol=https;AccountName=’ + $storageAccount + ‘;AccountKey=’ + $accountKey.Value

$AppSettings = @{}

$AppSettings = @{‘AzureWebJobsDashboard’ = $storageAccountConnectionString;

‘AzureWebJobsStorage’ = $storageAccountConnectionString;

‘FUNCTIONS_EXTENSION_VERSION’ = ‘~1’;

‘WEBSITE_CONTENTAZUREFILECONNECTIONSTRING’ = $storageAccountConnectionString;

‘WEBSITE_CONTENTSHARE’ = $storageAccount;

‘CUSTOMSETTING1’ = ‘CustomValue1’;

‘CUSTOMSETTING2’ = ‘CustomValue2’;

‘CUSTOMSETTING3’ = ‘CustomValue3’}

Set-AzureRMWebApp -Name $functionAppName -ResourceGroupName $resourceGroupName -AppSettings $AppSettings

# =========================================================================

$baseResource = Get-AzureRmResource -ExpandProperties | Where-Object { $_.kind -eq ‘functionapp’ -and $_.ResourceType -eq ‘Microsoft.Web/sites’ -and $_.ResourceName -eq $functionAppName }

$SourceFileContent = Get-Content -Raw $SourceFile

$functionFileName = ‘run.ps1’

#schedule – run every 1am every day

$props = @{

config = @{

‘bindings’ = @(

@{

‘name’ = ‘myTimer’

‘type’ = ‘timerTrigger’

‘direction’ = ‘in’

‘schedule’ = ‘0 0 1 * * *’

}

)

}

}

$props.files = @{$functionFileName = “$SourceFileContent”}

$newResourceId = ‘{0}/functions/{1}’ -f $baseResource.ResourceId, $functionName

# now deploy the function itself

New-AzureRmResource -ResourceId $newResourceId -Properties $props -ApiVersion 2015-08-01 -force

# =========================================================================

function Get-PublishingProfileCredentials($resourceGroupName, $webAppName)

{

$resourceType = “Microsoft.Web/sites/config”

$resourceName = “$webAppName/publishingcredentials”

$publishingCredentials = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType $resourceType

-ResourceName $resourceName -Action list -ApiVersion 2015-08-01 -Force

return $publishingCredentials

}

function Get-KuduApiAuthorisationHeaderValue($resourceGroupName, $webAppName)

{

$publishingCredentials = Get-PublishingProfileCredentials $resourceGroupName $webAppName

return (“Basic {0}” -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes((“{0}:{1}” -f

$publishingCredentials.Properties.PublishingUserName, $publishingCredentials.Properties.PublishingPassword))))

}

function UploadFile($kuduApiAuthorisationToken, $functionAppName, $functionName, $fileName, $localPath )

{

$kuduApiUrl = “https://$functionAppName.scm.azurewebsites.net/api/vfs/site/wwwroot/$functionName/modules/$fileName”

$result = Invoke-RestMethod -Uri $kuduApiUrl `

-Headers @{“Authorization”=$kuduApiAuthorisationToken;”If-Match”=”*”} `

-Method PUT `

-InFile $localPath `

-ContentType “multipart/form-data”

}

# =========================================================================

$accessToken = Get-KuduApiAuthorisationHeaderValue $resourceGroupName $functionAppName

$moduleFiles = Get-ChildItem ‘modules’

$moduleFiles | % {

Write-Host “Uploading $($_.Name) … ” -NoNewline

UploadFile $accessToken $functionAppName $functionName $_.Name $_.FullName

Write-Host -f Green ” [Done]”

}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s