A way to manually kick a Azure Function Timer Trigger Function when its been deployed


Introduction

At iThink 365 we have been building a few products around the Microsoft 365 Employee Experience. These products need to refresh information about the employees and so this is done using Azure Functions as Timer Trigger functions.

Something like this

Last week, I was chatting with one of my team and I showed them how they could manually kick off the timer trigger function. They exclaimed, “Woah, I had no idea you could do that!” I asked some more of the team and they said the same thing. So, I hope you have not either.

One of the attributes on the Timer Trigger is the RunOnStartup flag and it is important and seen as one of the best practices of Azure Functions to make sure that these are switched off,. This ensures that you don’t get your Azure Function firing randomly.

However, when developers are working on these Timer Triggers you want the Timer Trigger to run as soon as you start debugging the code. Having the RunOnStartUp flag off is a pain and often they get left on so that the code runs on startup. We do not want that behaviour where the flag gets left on.

Another scenario that you want to kick off the Timer Trigger is when a new customer joins and you want their user estate to be processed as soon as they subscribe to your product.

So, we need to be able to kick off the Timer Trigger function somehow.

How do we manually kick off a Timer Trigger function?

Solution

Well, it turns out you can call the Azure Function with a special endpoint and it is this one.

Using the URL:

https://%5Byour azure function url]/admin/functions/[YourAzureFunctionTimerTriggerFunctionName]

For our timer job above it would be like this:

https://doyfunction.azurewebsites.net/admin/functions/RefreshNewStartersCachesFunction

You can kick off the Timer Job, you also need either the master key or the function key from your Azure Function.

This can be retrieved by:

  • Browse to the Azure Portal (https://portal.azure.com)
  • Find your Azure Function
  • Click on App Keys under Functions
  • Copy the master key

Once we have the Azure Function function/master key, we need to call the endpoint. To do that we:

  • Using Postman
  • Create a request
  • Change the HTTP verb from GET to POST
  • Use your URL for your Trigger Function
  • Add a new header called
    • x-functions-key
  • use the function or master key as the value.
  • Click Send
  • You will receive an Accepted 202 response back if the request was successful.

That is it your timer job will have started.

An example is here:

If you receive an HTTP 404, and you are using an Application Setting to define your Timer Trigger schedule then check you have a valid value for the Application Setting in your configuration.

Hope you find this useful!

PowerShell: Script to Update SharePoint Content Type Document Template


Introduction

One of the great things about Content Types are that you can have a document template associated to the Content Type.

This means that when you create a new document a customised word template with its own look and feel can be used to guide the user through the process of filling the document and setting up the content type’s metadata.

Recently, we had the situation where we had content types being used across lots of site collections each for the different departments in the organisation.

One of the management overheads is when a document template needs to be updated. How can you do that programmatically using PowerShell?

Well the following script helps you get that done.

Solution

The PowerShell Script, Update-SPContentTypeDocumentTemplate.ps1 below does just that.

param
(
[Parameter(Mandatory=$true, HelpMessage='Url for Site Collection hosting content type')]
[string]$Url = "https://sharepoint.ithinksharepoint.com",
[Parameter(Mandatory=$true, HelpMessage='Name of the Content Type to apply document template to')]
[string]$ContentTypeName = "Policy Document",
[Parameter(Mandatory=$true, HelpMessage='File path of the document template to upload')]
[string]$DocumentTemplatePath = "",
[Parameter(Mandatory=$false, HelpMessage='Filename to store the file in SharePoint as')]
[string]$DocumentTemplateFileName = "",
[Parameter(Mandatory=$false, HelpMessage='Should derived child content types and list content types be updated?')]
[boolean]$UpdateChildren = $true
)
$site=Get-SPSite $Url;
if($site -ne $null)
{
$rootWeb = Get-SPWeb $Url;
$contentType = $rootWeb.ContentTypes | ?{$_.Name -eq $ContentTypeName};
if($contentType -ne $null -and [System.IO.File]::Exists($DocumentTemplatePath))
{
$templateFile = [System.IO.File]::OpenRead($DocumentTemplatePath);
$memoryStream = new-object System.IO.MemoryStream;
$templateFile.CopyTo($memoryStream);
if([String]::IsNullOrEmpty($DocumentTemplateFileName))
{
$DocumentTemplateFileName = [System.IO.Path]::GetFileName($DocumentTemplatePath);
}
$destinationUrl=[String]::Format("{0}/{1}/{2}", $rootWeb.ServerRelativeUrl, $contentType.ResourceFolder.Url, $DocumentTemplateFileName);
if(-not [String]::IsNullOrEmpty($contentType.DocumentTemplateUrl))
{
Write-Host "Checking Content Type Document Template Url: $contentType.DocumentTemplateUrl for file" -ForegroundColor White;
$checkFile = $rootWeb.GetFile($contentType.DocumentTemplateUrl);
if($checkFile.Exists)
{
Write-Host "File found at $contentType.DocumentTemplateUrl, removing" -ForegroundColor White;
$checkFile.Delete();
}
}
Write-Host "Checking for file @ $destinationUrl" -ForegroundColor White;
$checkFile=$rootWeb.GetFile($destinationUrl);
if($checkFile.Exists)
{
Write-Host "file found @ $destinationUrl, removing" -ForegroundColor White;
$checkFile.Delete();
}
Write-Host "Content Type Document Template not set or found " $contentType.Name -ForegroundColor White;
$checkFile = $contentType.ResourceFolder.Files.Add($destinationUrl, $memoryStream.ToArray());
$checkFile.Update();
Write-Host "Uploaded file $DocumentTemplatePath -> $destinationUrl for" $contentType.Name -ForegroundColor White;
$contentType.DocumentTemplate = $DocumentTemplateFileName;
$contentType.UpdateIncludingSealedAndReadOnly($UpdateChildren);
Write-Host "Applied Document Template $destinationUrl to " $contentType.Name " and updated content type (All Children Update Flag set? $UpdateChildren)" -ForegroundColor Green;
}
else{
Write-Error "Cannot find $ContentTypeName in $Url or cannot find document template file $DocumentTemplatePath, please check.";
}
}
else
{
Write-Host "Cannot find Site $Url" -ForegroundColor Yellow;
}
Write-Host "Finished";

So how do you use it?

Well you provide the URL of the site, the path to the document template and also the name of the Content Type.

It will access the site, check if the content type already has a document template, upload the selected document and configure the content type to use the new document template.

You can decide if you want to update all the child content types which have been assigned to document libraries. if you want to do this which is recommended then make sure you include the -UpdateChild switch.

Example

.\Update-SPContentTypeDocumentTemplate.ps1 –Url https://sharepoint -ContentTypeName "Policy Document" -DocumentTemplatePath "c:\dev\documents\policydocumenttemplate.dotx" -DocumentTemplateFileName "policydocumenttemplatev2.dotx" -UpdateChildren

So what would happen if you wanted to update a number of sites?

Well you can just get a list of the sites and pipe that array into the command and it will update the content type on each site.

Also the same technique could be used to update multiple content types on a number of sites.

Download Script

The PowerShell Script is part of the iThink SharePoint PowerShell GitHub Repository, which can be found here:

https://github.com/ithinksharepoint/PowerShell

Anyway, I hope you find the solution useful, please let me know if you did and also if you have some additions or changes then please share them!

All the best

Simon