One of the great new features in Azure is Azure Functions. Azure functions will let you run PowerShell scripts at a very low cost within an Azure tenant.  In this post I go through all the steps needed to set this up.

The example script that I’m trying to run is simple. I will export a site using PnP PowerShell. Using my ISE PowerShell I developed a script that looks like this:

[code lang=text]
$siteUrl = “…”

$cred = Get-Credential

Connect-PnPOnline -Url $siteUrl -Credentials $cred

Write-Host “Connected”

Get-PnPProvisioningSite -Out c:\temp\test.xml
[/code]

So how do I run the above script in my Azure function.

I’m going to start with the beginning, creating an Azure Function App.

Creating Azure Functions

Click on the green plus and in the Compute Section select Function App.

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell azurefucntion

Then in the form that appears complete the Appname and the rest of the form is completed for you. then to make things easier you might want to tick the box to pin to dashboard.

 

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell createfunctionapp1

After a while the PSAzureFunctions will be deployed and ready to use.

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell dashboard

When clicking on the Function App on the Dashboard I got the the following Overview screen:

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell overview

Time to look at the next steps.

I will need to run the PowerShell script so I’ll need to upload the script somewhere, but additionally I will need to upload the PnP Modules.

Uploading PnP PowerShell

In the overview screen I’m clicking on Platform features. Then in Platform features I click on Development tools -> Advanced tools(Kudo)

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell platformfeatures

Kudo is a set of tools that will make it easy to upload files to your Azure Function.

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell kudo

In the Debug console  I select PowerShell to get me to an interface that will let me upload my module files.

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell powershellkudo

The next step is to create a Modules folder. You could simply type mkdir Modules in the Console, but I’m going to use the interface instead.

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell newfolder

 

Once the Modules folder has been created I’m clicking on the folder modules folder and I’m dragging my  PnPPowerShell Module to this folder from C:\Users\useraccount\AppData\Local\Apps\SharePointPnPPowerShellOnline\Modules

If you haven’t got PnP PowerShell installed locally then you can install it from here: https://github.com/SharePoint/PnP-PowerShell/releases

 

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell uploaded

Ok, so good so far. Time to get some PowerShell scripts running.

I’m going back to my Azure Function and click on the big plus sign next to Functions.

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell platformfeatures

Now I’m ending up in a dialog that isn’t really giving me what I need:

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell createfunction

So I click on the link create your own custom function.

 

In the sea of templates, I’m filtering by PowerShell:

 

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell templates

And I get the option of 3 templates:

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell templates3

Notice that all three templates have been marked with Preview.So all of this is very much bleeding edge.

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell bleeding

In the template I’m selecting the TimerTrigger-PowerShell template.

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell timertrigger

I’m updating the name of the function to GetTemplate and click on Create

 

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell functioncreated

Ok, now we’re getting to the point of running PowerShell script.

Running PowerShellConverting PowerShell

First i’m copying the PowerShell from the beginning of the post to my Azure Function.

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell copypowershell

then I click on Save and run and in the Logs dialog I can see some output from my PowerShell script.

 

2017-05-18T14:28:44  Welcome, you are now connected to log-streaming service.

2017-05-18T14:29:44  No new trace in the past 1 min(s).

2017-05-18T14:30:01.061 Function started (Id=2781541b-8485-46a2-9332-a1a78486a1fd)

2017-05-18T14:30:02.751 PowerShell Timer trigger function executed at:05/18/2017 14:30:02

2017-05-18T14:30:02.769 Function completed (Success, Id=2781541b-8485-46a2-9332-a1a78486a1fd, Duration=1699ms)

2017-05-18T14:31:44  No new trace in the past 1 min(s).

2017-05-18T14:32:44  No new trace in the past 2 min(s).

2017-05-18T14:33:44  No new trace in the past 3 min(s).

2017-05-18T14:34:44  No new trace in the past 4 min(s).

2017-05-18T14:34:56.393 Function started (Id=f4ba1c6a-bb37-4c5e-9b0b-e0283479ea2d)

2017-05-18T14:34:56.896 : Cannot process command because of one or more missing mandatory parameters: Credential.

at run.ps1: line 3

+ 

+ 

    + CategoryInfo          : InvalidArgument: (:) [Get-Credential], ParameterBindingException

    + FullyQualifiedErrorId : MissingMandatoryParameter,Microsoft.PowerShell.Commands.GetCredentialCommand,run.ps1

2017-05-18T14:35:00.157 Function started (Id=36e42613-f8c2-403d-a821-df218ca5bd67)

2017-05-18T14:35:00.984 : Cannot process command because of one or more missing mandatory parameters: Credential.

at run.ps1: line 3

+ 

+ 

    + CategoryInfo          : InvalidArgument: (:) [Get-Credential], ParameterBindingException

    + FullyQualifiedErrorId : MissingMandatoryParameter,Microsoft.PowerShell.Commands.GetCredentialCommand,run.ps1

2017-05-18T14:36:14.613 Connect-PnPOnline : The term 'Connect-PnPOnline' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

at run.ps1: line 5

+ Connect-PnPOnline

+ _________________

    + CategoryInfo          : ObjectNotFound: (Connect-PnPOnline:String) [], CommandNotFoundException

    + FullyQualifiedErrorId : CommandNotFoundException

2017-05-18T14:36:14.675 Connect-PnPOnline : The term 'Connect-PnPOnline' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

at run.ps1: line 5

+ Connect-PnPOnline

+ _________________

    + CategoryInfo          : ObjectNotFound: (Connect-PnPOnline:String) [], CommandNotFoundException

    + FullyQualifiedErrorId : CommandNotFoundException

2017-05-18T14:36:14.722 Write-Host : A command that prompts the user failed because the host program or the command type does not support user interaction. Try a host program that supports user interaction, such as the Windows PowerShell Console or Windows PowerShell ISE, and remove prompt-related commands from command types that do not support user interaction, such as Windows PowerShell workflows.

at run.ps1: line 7

+ Write-Host

+ __________

    + CategoryInfo          : NotImplemented: (:) [Write-Host], HostException

    + FullyQualifiedErrorId : HostFunctionNotImplemented,Microsoft.PowerShell.Commands.WriteHostCommand

2017-05-18T14:36:14.956 Write-Host : A command that prompts the user failed because the host program or the command type does not support user interaction. Try a host program that supports user interaction, such as the Windows PowerShell Console or Windows PowerShell ISE, and remove prompt-related commands from command types that do not support user interaction, such as Windows PowerShell workflows.

at run.ps1: line 7

+ Write-Host

+ __________

    + CategoryInfo          : NotImplemented: (:) [Write-Host], HostException

    + FullyQualifiedErrorId : HostFunctionNotImplemented,Microsoft.PowerShell.Commands.WriteHostCommand

2017-05-18T14:36:15.191 Get-PnPProvisioningSite : The term 'Get-PnPProvisioningSite' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

at run.ps1: line 9

+ Get-PnPProvisioningSite

+ _______________________

    + CategoryInfo          : ObjectNotFound: (Get-PnPProvisioningSite:String) [], CommandNotFoundException

    + FullyQualifiedErrorId : CommandNotFoundException

2017-05-18T14:36:15.191 Function completed (Failure, Id=36e42613-f8c2-403d-a821-df218ca5bd67, Duration=75045ms)

2017-05-18T14:36:15.238 Get-PnPProvisioningSite : The term 'Get-PnPProvisioningSite' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

at run.ps1: line 9

+ Get-PnPProvisioningSite

+ _______________________

    + CategoryInfo          : ObjectNotFound: (Get-PnPProvisioningSite:String) [], CommandNotFoundException

    + FullyQualifiedErrorId : CommandNotFoundException

2017-05-18T14:36:15.253 Function completed (Failure, Id=f4ba1c6a-bb37-4c5e-9b0b-e0283479ea2d, Duration=75045ms)

2017-05-18T14:36:15.285 Exception while executing function: Functions.GetTemplate. Microsoft.Azure.WebJobs.Script: PowerShell script error. System.Management.Automation: Cannot process command because of one or more missing mandatory parameters: Credential.

2017-05-18T14:36:15.316 Exception while executing function: Functions.GetTemplate. Microsoft.Azure.WebJobs.Script: PowerShell script error. System.Management.Automation: Cannot process command because of one or more missing mandatory parameters: Credential.

2017-05-18T14:36:15.519 mscorlib: Exception while executing function: Functions.GetTemplate. Microsoft.Azure.WebJobs.Script: PowerShell script error. System.Management.Automation: Cannot process command because of one or more missing mandatory parameters: Credential.

 

Ok, this is a bit harder than initially expected.

There are a few issues that can be identified.

  1. The Write-Host is failing
  2. the Get-Credential isn’t working either.
  3. PnP PowerShell isn’t loaded

Instead of Write-Host I can use Write-Output.

Instead of the Get-Credential I can use

New-Object -typename System.Management.Automation.PSCredential($username, $encpassword)

To load PnP PowerShell I’m updating the $env:PSModulePath variable in PowerShell.

With the above changes in place I’m running the below script

 

[code lang=text]
$siteUrl = “https:/ /mytenant.sharepoint.com”
$password = “MyVerySecretPassword”
$username = “admin@mytenant.onmicrosoft.com”

$encpassword = convertto-securestring -String $password -AsPlainText -Force
$cred = New-Object -typename System.Management.Automation.PSCredential($username, $encpassword)
$path = “D:\home”

$env:PSModulePath += “;$path\Modules\SharePointPnPPowerShellOnline”

Write-Output “Running PnP version:”
(Get-Module -Name SharePointPnPPowerShellOnline -ListAvailable).Version

Connect-PnPOnline -Url $siteUrl -Credentials $cred
Write-Output $(“Connected to $siteUrl”)
$web = Get-PnPWeb
Write-Output $($web.Url)
Get-PnPProvisioningTemplate -Web $web -Out “d:\home\template.xml”
[/code]

Ok, that runs without any error messages and when I look at my diagnostic console I can see my template:

Office 365 - Azure - Running PnP PowerShell using Azure Functions Microsoft Azure, Microsoft Office 365, Microsoft SharePoint, PowerShell done

Then I reran the script and I got some more errors:

 

017-05-18T15:43:59.030 Get-PnPProvisioningTemplate : A command that prompts the user failed because the host program or the command type does not support user interaction. The host was attempting to request confirmation with the following message: File d:\home\template.xml exists, overwrite?

at run.ps1: line 24

+ Get-PnPProvisioningTemplate

+ ___________________________

    + CategoryInfo          : WriteError: (:) [Get-PnPProvisioningTemplate], HostException

    + FullyQualifiedErrorId : EXCEPTION,SharePointPnP.PowerShell.Commands.Provisioning.GetProvisioningTemplate

2017-05-18T15:43:59.030 Function completed (Failure, Id=c90f3b6d-e30d-4795-aba0-48ff8660acdb, Duration=3471ms)

2017-05-18T15:43:59.077 Exception while executing function: Functions.GetTemplate. Microsoft.Azure.WebJobs.Script: PowerShell script error. System.Management.Automation: A command that prompts the user failed because the host program or the command type does not support user interaction. The host was attempting to request confirmation with the following message: File d:\home\template.xml exists, overwrite?.

Adding -Force to the Get-PnPProvisioningTemplate ensures that when the template file already exists the Cmdlet will run without asking the user to overwrite the file.

Get-PnPProvisioningTemplate -Web $web -Out “d:\home\template.xml” -Force

 

Do you want help with setting up PowerShell scripts in your Azure tenant please feel free to contact me and I’m happy to help.

 

 

 

 

Avatar for Pieter Veenstra

By Pieter Veenstra

Business Applications Microsoft MVP working as a Principal Architect at HybrIT Services Ltd. You can contact me using contact@sharepains.com

7 thoughts on “Office 365 – Azure – Running PnP PowerShell using Azure Functions”
  1. I am using a queue triggered azure function to create subsite and apply templates under a site collection using PnP Powershell. The function works well for a single request however if I put in two requests immediately one after the other, the execution fails with the error “The object is used in the context different from the one associated with the object.” at a point where I use the New-PnPWeb command. Since the function is queue triggered, the function is triggered twice, one for each site. Any pointers as to why these requests conflict ?

    I see the same behaviour for two different Azure functions running on two separate site collections !

    1. I would expect that you will see the same behaviours when you run the scripts from any location other than azure function apps. I’m not 100% sure what exactly is happening but I’m expecting that your context is going stale. So that when you create a site collection while another site collection is being created the actual values and the values in your context don’t match resulting in an error. You could probably replicate the same situation with two PowerShell windows running the site collection creation at the same time. The way around it is probably to retry on error and put a pause of 5-10 minutes in.

      1. Cannot recreate this in two separate powershell windows on my local machine. Tried to fire “New-PnPWeb” command on the same site collection in two windows, worked well. The connections for the two windows are independent of each other anyway.

        Yes, even I thought that the context is getting messed up but cannot understand why if the two separate queue requests trigger two threads of the function. As a workaround I had to make the queue requests execute sequentially.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from SharePains by Microsoft MVP Pieter Veenstra

Subscribe now to keep reading and get access to the full archive.

Continue Reading

%d bloggers like this: