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 :
- Coffee
- Create Azure Resource Group – ie. a bucket for all the elements
- Create Azure Storage Account
- Create Azure Function App
- Update some Azure Function App Settings
- Upload the Azure Function code (PowerShell)
- Upload the MODULE files also
- 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.
1. Coffee (and login)
Execute the command to connect to Azure – you get a dialog box for username/password :
2. Create Azure Resource Group

3. Create Azure Storage Account

4. Create Function App

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

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.

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)

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]”
}