Azure

Learn how to host PowerShell Universal in Azure.

PowerShell Universal is an ASP.NET Core web application and can be hosted in Windows Azure Web Apps.

Container Web App

Container web apps allow for using Docker images as web apps in Azure. Within the Azure portal, you can create a Docker Container web app by using the App Services \ Create Web App wizard.

Once you have selected a resource group, assigned a name and selected a compute plan, you will be able to create the web app.

Next, you'll need to deploy the image to your web app. To do so, select the Deployment Center and configure the image to pull. You can either pull a static tagged version (like 2.7.3) or pull the latest and your web app will automatically stay up to date with new PowerShell Universal releases.

For production environments, we suggest setting a tagged version to avoid unintentional updates to your container when it restarts. By default, Azure will automatically update containers when a tag, such as latest, is updated. This will allow you to control updates to your PowerShell Universal version.

Azure Storage and LiteDB

For single instance systems, you can use an Azure Storage Account with a File Share to store the configuration and database.

Do not use an Azure Storage Account if you chose to use git integration. PowerShell Universal performance will be severely degraded if you use this configuration due to the performance of Azure File Shares.

We'll need to configure the Azure Storage Account for file shares to store the data for this web app. Within your storage account, create a new File Share that is transaction optimized.

Back in your App Service, you can setup a Path mapping to the file share we just created. In my example, I've set the mount path to /Data. This is where the configuration and database will be stored.

Finally, we need to configure PowerShell Universal to store data on our file share. On the Application settings tab, set the Data__ConnectionString and Data__RepositoryPath to store data on the file share.

Restart the App Service and login to your new PowerShell Universal instance. You'll see that data generated by PowerShell Universal is being stored on the share.

Git and SQL

If you choose to use git integration in PowerShell Universal, we recommend setting up a SQL server and database for storage. Git will be used to synchronize configuration files when the container is started. SQL will store the git configuration settings alongside resources like jobs, app tokens and identities.

You'll need an Azure SQL database to get started. Once you create the resource, you will need to copy the connection string from the database to provide to PowerShell Universal.

Ensure that you have allowed Azure services to access the database.

To enable SQL support, you should set the plugins within PowerShell Universal to use the SQL plugin in the Application Configuration for your web app.

Create a Plugins__0 setting with the value SQL. Next, set the Data__ConnectionString value to your SQL server database.

Once you have SQL configured, you can start your container. The database schema will be created as the container starts. Next, you'll need to configure git within PowerShell Universal by clicking Settings \ Git. Enter your remote, branch, username, password or personal access token, and synchronization mode. Push-only is not recommended in this configuration because container state is lost between restarts. Ensure that the initialization mode is set to Clone.

Git settings are stored in your SQL database and will be retrieved each time the container is started.

Forwarded Headers

Containers are typically hosted behind a reverse proxy and will not be aware of the actual external URL without additional configuration. In order to ensure that systems that require the external URL, like OpenID Connect, receive the proper information, you will need to set the ASPNETCORE_FORWARDEDHEADERS_ENABLED environment variable to true.

For more information, you can read this blog post from the Microsoft.

Standard Web App

Manually Creating a Web App

Within the Azure Portal, you will need to create a new Web App resource. PowerShell Universal currently requires the .NET 6 runtime stack. You can use either Linux or Windows.

If you choose a Windows hosting plan rather than a Linux hosting plan in Azure when configuring your WebApp then you need to choose a Basic Plan (B1) or higher to be able to use 64-bit apps. You also have to go to Settings > Configuration > General setting > Platform and select 64-bit before you run the Publish-AzWebApp command, or it will fail to install.

Startup Command (Linux Only)

When hosting in a Linux environment, you will need to set the startup command under Settings \ Configuration \ General Settings \ Startup Command to the following.

dotnet Universal.Server.dll

In the below example, we'll use the Azure PowerShell module to deploy the Web App manually.

You'll first need to install Azure PowerShell.

Install-Module Az

Once installed, you'll need to connect to your subscription.

Connect-AzAccount

Deploy Windows Files

If you are using Windows, you will need to download the Windows ZIP file. This will download the latest version of PowerShell Universal.

$LatestVersion = Invoke-RestMethod https://imsreleases.blob.core.windows.net/universal/production/v3-version.txt
Invoke-WebRequest "https://imsreleases.blob.core.windows.net/universal/production/$LatestVersion/Universal.win7-x64.$LatestVersion.zip" -OutFile .\Universal.zip

Deploy Linux Files

If you are using Linux, you will need to download the Linux ZIP file. This will download the latest version fo PowerShell Universal.

$LatestVersion = Invoke-RestMethod https://imsreleases.blob.core.windows.net/universal/production/v3-version.txt
Invoke-WebRequest "https://imsreleases.blob.core.windows.net/universal/production/$LatestVersion/Universal.linux-x64.$LatestVersion.zip" -OutFile .\Universal.zip

Now that we have the Az module configured and the Universal ZIP downloaded, we can deploy the Web App.

$Parameters = @{
    Force = $true
    ResourceGroupName = 'psudemo2_group'
    Name = 'psudemo2'
    ArchivePath = '.\Universal.zip'
}
Publish-AzWebApp @Parameters

You can check in Azure under Deployment Center > Logs for Status Success (Active) to ensure files deployed / installed successfully.

Setting Adjustments Required

These settings can be set within the Configuration tab within the Application settings.

JWT Signing Key

The default JWT signing key is not of a sufficient length and will need to be updated. This can be done in appsettings.json or by using environment variables.

appsettings.json

  "Jwt": {
    "SigningKey": "xXyt9UpJKB4Pb*4$hprd!JJoyOcK4ZOV**O7Hug9&@gYHc$",
    "Issuer": "IronmanSoftware",
    "Audience": "PowerShellUniversal"
  },

Environment Variable

$Env:Jwt__SigningKey = 'xXyt9UpJKB4Pb*4$hprd!JJoyOcK4ZOV**O7Hug9&@gYHc$'

API URL

Azure Web Apps use a reverse proxy and PowerShell Universal does not detect the external URL appropriately. When running jobs, Universal uses the Management API to automatically look up job, script and schedule information. This means that this will fail if it cannot correctly address the external API URL.

The API URL should be the external HTTP address of your Web App. You can update this in appsettings.json or by using an environment variable.

appsettings.json

"Api": {
 "Url": "https://psudemo.azurewebsites.net"
 },

Environment Variable

$Env:Api__Url = "https://psudemo.azurewebsites.net"

NodeName

You can set the name of the PowerShell Universal instance by specifying the NodeName. This will ensure that restarts will not affect the PowerShell Universal database. This is not required for LiteDB installations.

$Env:NodeName = "psuazure"

PORT and WEBSITES_PORT (Linux Only)

To override the default port in a Linux web app, you need to set the PORT and WEBSITES_PORT setting to 5000.

After publishing the Web App, view your PowerShell Universal instance by navigating to the Web App's URL.

Persistent Storage

The default appsettings.json file will store the database and configuration files in a non-persistent location. You can add environment variables to move them to persistent storage within your web app.

Data__ConnectionString

The Data__ConnectionString environment variable sets the location of the database. You will have to ensure that you enable a "shared" connection for LiteDB to function properly in Azure. Set the value to the following.

filename=D:\home\Data\PowerShellUniversal\database.db;Connection=shared

Data__RepositoryPath

The Data__RepositoryPath environment variable sets the location of the configuration files for Universal. Set the value to the following.

D:\home\Data\PowerShellUniversal\Repository

Updating your Web App

When a new version of PowerShell Universal is released, you will need to update the application files for your Web App. We recommend removing the application directory and redeploying the files. The database and configuration files are not stored in the application directory.

You can delete the files for your Web App by using the Kudu command API. Your Kudu credentials use Basic authentication and are the same as your deployment credentials.

To delete all the files in your Web App, issue the following command.

$Parameters = @{
   Uri = "https://psudemo2.scm.azurewebsites.net/api/command"
   Credential = (Get-Credential)
   Body = (@{
      command = "rd /s /q D:\home\site\wwwroot"
      dir = "D:\home\site\wwwroot"
   } | ConvertTo-Json)
}

Invoke-RestMethod @Parameters

Once you've delete the application files, you can redeploy them by running the manual creation steps again.

Application Gateway

You can configure PowerShell Universal to run behind an Application Gateway within Azure. This is helpful for providing load balancing and high availability to multiple PowerShell Universal instances.

First, configure a backend pool that targets one or more Azure Web Apps running PowerShell Universal.

For the backend settings, you will want to ensure you are using HTTPS with a well known CA certificate. Cookie-based affinity is required to ensure that sessions are sticky to a individual node.

In order to allow Azure to serve the proper web app, you will need to ensure that the Override with new host name setting is configured. Use the host name for the backend target.

Ensure that the backend pool rule is configured as the target and not redirection.

Configure a header rewrite rule to pass along the public facing host name as the X-Forwarded-Host header. PowerShell Universal will use this to internally construct URLs.

The above rewrite rule is a requirement of OpenID Connect and SAML2 authentication methods.

Finally, you can configure your Application Gateway public IP using a DNS provide to a custom host name. Create an A record in your DNS management.

Last updated

Copyright 2022 Ironman Software