Running Powershell Web Jobs on Azure websites
Update: Web Jobs now natively support PowerShell scripts. You can upload a zip file containing a .ps1 file and it will be executed without further configurations.
Just last week we announced a series of new features for the Windows Azure platform. One of those features is Web Jobs support for Windows Azure Web Sites. Web Jobs enable you to run custom jobs on your web site, either on-demand, scheduled or continuously. However, some people have already wondered why there is no support for Powershell scripts (.ps1). In this post I’m going to show how you can use Powershell scripts to run as a Web Job on Windows Azure Web Sites.
Setting up an Azure Web Site
The first step is to quick create an empty Azure Web Site – for the purpose of this post, we don’t need actual web content. So, just create an Azure Web Site through the Azure Management Portal.
Once the site is created (amazing it takes less than 10 seconds!), you should now see the ‘Web Jobs' (preview) section.
In this post, we’re going to be using a very basic PowerShell script to be executed on the Web Site – the script will just retrieve the list of actively running processes on the server by invoking the Get-Process cmdlet.
Verifying it doesn’t work
Of course we want to push our luck and upload a .ps1 file to create a Web Job. When you do this, the operation will fail and you’ll be presented with the following error message in the portal:
Running a PowerShell Web Job
We now have validated that we cannot use a PowerShell script to create a Web Job, but how can we achieve this? As you may know, Powershell can be invoked from the commandline, by means of PowerShell.exe. This is exactly what we’re going to do to use PowerShell as a Web Job.
First step is to create a Windows command file (.cmd or .bat) which will invoke PowerShell.exe and providing it our PowerShell commands. This is the contents of our ListProcessesPS.cmd file:
PowerShell.exe -Command "& {Get-Process}"
After zipping up this file we can now create a Web Job through the Azure Management portal:
The Job is created successfully and we are ready to launch it. Once the Last Run Result shows ‘Success’ we can view the outcome of the Job by navigating to the logs.
Below screenshot shows the outcome of running the PowerShell command on our Azure Web Site!
Using a separate PowerShell script – Take 1
Of course, this solution is not optimal if you have multi-line, complex PowerShell scripts. Ideally we want to be able to create a PowerShell script file that is separate from the command script. Looking at the PowerShell.exe command-line reference, there is a parameter that allows us to invoke a PowerShell script, namely the –File parameter. So we adapt the command script accordingly:
PowerShell.exe -File Get-Processes.ps1
We then create a zip file containing both the ps1 and cmd files and upload it to create a new Web Job. However, when you run the Web Job, we don’t get the outcome we expected. We receive an error file, which indicates that the PowerShell script we’re trying to execute is not digitally signed and therefore cannot be executed.
Using a separate PowerShell script – Take 2
Reverting back to the PowerShell.exe command-line reference, another command-line parameter comes to the rescue to get around this digital signature issue: –ExecutionPolicy. We update the Windows command file as follows:
PowerShell.exe -ExecutionPolicy RemoteSigned -File Get-Processes.ps1
What’s happening here is that we tell PowerShell to run all local scripts and only require a digital signature for scripts that are being downloaded from the Internet.
We update the zip file with the updated Windows command file and the PowerShell script and create a new Web Job. When running the Job, we finally get the expected results!
Conclusion
As you’ve seen, there is actually a way to run PowerShell scripts as Web Jobs on Windows Azure Web Sites. You currently need to invoke it through an intermediate Windows command file instead of natively supporting .ps1 files, but in the end we got a workable solution.
Did you know that you can try Windows Azure for free?
Comments
Anonymous
February 24, 2014
I'm trying to run powershell with the Azure cmdlet i.e. Get-AzureRole but it's not working. The error file contains: Get-AzureRole : The term 'Get-AzureRole' is not recognized as the name of a [02/25/2014 13:51:00 > 782685: ERR ] cmdlet, function, script file, or operable program. Native PS code runs fine. But I want to use Azure Powershell cmdlet. Is there a way to get that working inside a web job?Anonymous
February 27, 2014
Hi Nick This is cool stuff. Is there anyway from an uploaded Powershell script / job to get to the Connection Strings for the Web site ? We have a pair of Web Sites / SQL Azure DBs , ie for UAT and Production , so the websites have different SQL connection strings. Is there a way to get to the Connection String for the Web site from Powershell , ie so it runs against correct DB in my case ? I can work around by looking @ APPSETTING_WEBSITE_SITE_ env var and setting relevant connection string , but obviously means in 2 places / would have to reupload the script etc cheers AndyAnonymous
March 03, 2014
@Andy There's different options. Either you access the web.config straight from your PS script. However, from PowerShell the easiest solution would be to leverage the Get-AzureWebSite cmdlet: Get-AzureWebsite -Name MySite | select ConnectionStringsAnonymous
March 03, 2014
@Fardau You could add an Import-Module Azure.ps1 in your PS script and include the Azure.ps1 script (from Azure PowerShell cmdlets) inside the zip file.Anonymous
March 03, 2014
The comment has been removedAnonymous
March 03, 2014
Just to prove that everything "works," I created a webjob just like the example in this post and it worked like one would expect. So what's different about the output of the Invoke-RestMethod cmdlet than the output of the Get-Process cmdlet that it deals with output buffers differently? I'm invoking them the same way, via the Powershell.exe -Command "& {<command>}" syntax. FWIW, when I didn't use the "& {<command>}", the job would just report as failed, but with the same error output. Now it reports as success.Anonymous
March 04, 2014
@Matthew I've tried running an Invoke-RestMethod myself and got it working correctly - the output shows the results of the REST call. This is the command I'm running: PowerShell.exe -Command "& {Invoke-RestMethod -Uri www.discoposse.com/index.php/feed -Method Get}" Just wondering, what does your command output when run locally from a cmd shell? Feel free to DM me on Twitter (@nicktrog)Anonymous
March 04, 2014
Same error messages in the log file when I just upload a zipped up .ps1 file that has the commands to run.Anonymous
March 04, 2014
The comment has been removedAnonymous
March 04, 2014
So I figured out the problem with the Invoke-RestMethod (and the Invoke-WebRequest, too, I think) and this phantom progress bar. There is a variable $ProgressPreference the value of which needs to be changed from the default ("Continue") to "SilentlyContinue" before executing your actual script that spawns the progress bar and this takes care of it. I went ahead and set it back to its default after my script was finished. Phew!Anonymous
November 02, 2016
So how do I get that powershell output to be the response to the webhook?