This blog post will show you how you can upgrade Azure Bastion from the Basic SKU to the Standard SKU (Tier) via the use of an Azure PowerShell script.
Azure Bastion is an Azure PaaS service that you provision inside a virtual network (VNet), preferably the HUB VNet. It allows you to securely connect to your Azure virtual machines (VMs) via RDP or SSH, and this is done directly from the Azure portal over SSL. When you use Azure Bastion, your VMs do not need a Public IP Address (PIP), agent, or special client software to be able to connect to them.
Currently, Azure Bastion is available in two SKUs: Basic and Standard.
- The Basic SKU provides basic functionality, which enables Azure Bastion to manage RDP/SSH connectivity to virtual machines (VMs) without exposing public IP addresses (PIP) on any of those VMs.
- The Standard SKU enables premium features, like host scaling, specifying custom inbound ports when using Azure Bastion, etc.
If you want to read some more about Azure Bastion SKUs, you can do so via the following Microsoft Docs link: Azure Bastion SKUs documentation
You can upgrade Azure Bastion Basic SKU to the Standard SKU through the Azure Portal, but to automate and speed up this process, I wrote the below Azure PowerShell script, which does all of the following:
- Remove the breaking change warning messages.
- Change the current context to the subscription holding the Azure Bastion host, if the subscription exists; otherwise, exit the script.
- Save the Bastion host if it exists in the subscription as a variable and check if it uses the Basic SKU; if so, exit the script, otherwise the script will continue.
- Store the specified set of Azure Bastion host tags in a hash table.
- Upgrade Bastion to Standard SKU if Basic SKU is currently set.
To use the script, copy and save it as Upgrade-AzureBastion-Basic-SKU-to-Standard-SKU.ps1 or download it from GitHub. Then run the script from Windows Terminal, Visual Studio Code, or Windows PowerShell. Or you can simply run it from Cloud Shell.
If you want, you can also look at my previous blog posts, which can help you securely deploy and configure Azure Bastion and all associated resources: Azure Bastion: Azure PowerShell deployment script, Azure Bastion: Set the minimum required roles to access a virtual machine and Azure Bastion: Set Azure Bastion NSG Inbound security rules on the Target VM Subnet with Azure PowerShell
Prerequisites
- An Azure subscription.
- An Azure Administrator account with the necessary RBAC roles.
- An existing Azure Bastion host.
- At least Azure Az PowerShell module version 8.1.0 and Az.Network module version 4.18.1

Azure PowerShell script
If you are not running the script from Cloud Shell, don’t forget to sign in with the Connect-AzAccount cmdlet to connect your Azure account.

If you want to validate or know the Bastion SKU for your Bastion host before running the script and without opening the Azure Portal. First of all, set the context to the subscription holding the Azure Bastion host(s), and then run the following Azure PowerShell cmdlets:
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
## Get Bastion SKU
$bastion = Get-AzBastion | Where-Object Name -Match <your Bastion host name or abbreviation>
Write-Host $bastion.SkuText
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


<#
.SYNOPSIS
A script used to upgrade Azure Bastion Basic SKU to Standard SKU with an instance count of two.
.DESCRIPTION
A script used to upgrade Azure Bastion Basic SKU to Standard SKU with an instance count of two.
The script will do all of the following:
Remove the breaking change warning messages.
Change the current context to the subscription holding the Azure Bastion host, if the subscription exists; otherwise, exit the script.
Save the Bastion host if it exists in the subscription as a variable and check if it uses the Basic SKU; if so, exit the script, otherwise the script will continue.
Store the specified set of Azure Bastion host tags in a hash table.
Upgrade Bastion to Standard SKU if Basic SKU is currently set.
** Keep in mind upgrading Bastion to the Standard SKU can take up to 6 minutes. **
.NOTES
Filename: Upgrade-AzureBastion-Basic-SKU-to-Standard-SKU.ps1
Created: 03/10/2022
Last modified: 05/03/2023
Author: Wim Matthyssen
Version: 2.0
PowerShell: Azure Cloud Shell or Azure PowerShell
Requires: PowerShell Az (v8.1.0) and Az.Network (v4.18.0)
Action: Change variables were needed to fit your needs.
Disclaimer: This script is provided "as is" with no warranties.
.EXAMPLE
Connect-AzAccount
Get-AzTenant (if not using the default tenant)
Set-AzContext -tenantID "<xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx>" (if not using the default tenant)
.\Upgrade-AzureBastion-Basic-SKU-to-Standard-SKU <"your azure bastion host subscription name here"> <"your bastion host name here">
-> .\Upgrade-AzureBastion-Basic-SKU-to-Standard-SKU sub-hub-myh-management-01 bas-hub-myh-01
.LINK
https://wmatthyssen.com/2022/10/04/azure-bastion-upgrade-basic-sku-to-standard-sku-with-azure-powershell/
#>
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
## Parameters
param(
# $subscriptionName -> Name of the subscription holding the Azure Bastion host
[parameter(Mandatory =$true)][ValidateNotNullOrEmpty()] [string] $subscriptionInputName,
# $bastionName -> Name of the Azure Bastion host
[parameter(Mandatory =$true)][ValidateNotNullOrEmpty()] [string] $bastionInputName
)
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
## Variables
$bastionSkuStandard = "Standard"
$bastionScaleUnit = "2"
$global:currenttime= Set-PSBreakpoint -Variable currenttime -Mode Read -Action {$global:currenttime= Get-Date -UFormat "%A %m/%d/%Y %R"}
$foregroundColor1 = "Green"
$foregroundColor2 = "Yellow"
$foregroundColor3 = "Red"
$writeEmptyLine = "`n"
$writeSeperatorSpaces = " - "
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
## Remove the breaking change warning messages
Set-Item Env:\SuppressAzurePowerShellBreakingChangeWarnings "true" | Out-Null
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
## Write script started
Write-Host ($writeEmptyLine + "# Script started. Without errors, it can take up to 8 minutes to complete" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
## Change the current context to the subscription holding the Azure Bastion host, if the subscription exists; otherwise, exit the script
Get-AzSubscription -SubscriptionName $subscriptionInputName -ErrorVariable subscriptionNotPresent -ErrorAction SilentlyContinue | Out-Null
if ($subscriptionNotPresent) {
Write-Host ($writeEmptyLine + "# Subscription with name $subscriptionInputName does not exist in the current tenant" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor3 $writeEmptyLine
Start-Sleep -s 3
Write-Host -NoNewLine ("# Press any key to exit the script ..." + $writeEmptyLine)`
-foregroundcolor $foregroundColor1 $writeEmptyLine;
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null;
return
} else {
Set-AzContext -Subscription $subscriptionInputName | Out-Null
Write-Host ($writeEmptyLine + "# Subscription with name $subscriptionInputName in current tenant selected" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine
}
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
## Save the Bastion host if it exists in the subscription as a variable and check if it uses the Basic SKU; if so, the script will continue; otherwise, exit the script
$bastionObject = Get-AzBastion | Where-Object Name -Match $bastionInputName
# Check if a Bastion host exists in the subscription; otherwise, exit the script
if ($null -eq $bastionObject){
Write-Host ($writeEmptyLine + "# No Bastion host exists in the current subscription, please select the correct context and rerun the script" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor3 $writeEmptyLine
Start-Sleep -s 3
Write-Host -NoNewLine ("# Press any key to exit the script ..." + $writeEmptyLine)`
-foregroundcolor $foregroundColor1 $writeEmptyLine;
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null;
return
}
# Check if the Bastion host is running the Basic SKU; otherwise, exit the script
if ($bastionObject.SkuText.Contains("Standard")) {
Write-Host ($writeEmptyLine + "# Bastion host already using the Standard SKU" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor3 $writeEmptyLine
Start-Sleep -s 3
Write-Host -NoNewLine ("# Press any key to exit the script ..." + $writeEmptyLine)`
-foregroundcolor $foregroundColor1 $writeEmptyLine;
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null;
return
}
Write-Host ($writeEmptyLine + "# Bastion host variable created" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
## Store the specified set of Azure Bastion host tags in a hash table
$bastionTags = (Get-AzResource -ResourceGroupName $bastionObject.ResourceGroupName -ResourceName $bastionObject.Name).Tags
Write-Host ($writeEmptyLine + "# Specified set of tags available to add" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
## Upgrade Bastion to Standard SKU if Basic SKU is currently set
$bastionName = $bastionObject.Name
Write-Host ($writeEmptyLine + "# Upgrading bastion host $bastionName to the $bastionSkuStandard SKU, which can take up to 6 minutes to complete" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine
# Upgrade Bastion host to Standard SKU and 2 Scale Units
Set-AzBastion -InputObject $bastionObject -Sku $bastionSkuStandard -ScaleUnit $bastionScaleUnit -Force | Out-Null
# Set tags on Bastion host
Set-AzBastion -InputObject $bastionObject -Tag $bastionTags -Force | Out-Null
Write-Host ($writeEmptyLine + "# Bastion host $bastionName running with Standard SKU and $bastionScaleUnit Scale Units" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
## Write script completed
Write-Host ($writeEmptyLine + "# Script completed" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine
## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


I hope this Azure PowerShell script is useful for you whenever you need to upgrade an existing Bastion host to the Standard SKU.
If you have any questions or recommendations about it, feel free to contact me through my Twitter handle (@wmatthyssen) or to just leave a comment.
Pingback: Azure Bastion: Switch Standard SKU to Basic SKU with Azure PowerShell – Wim Matthyssen
Pingback: Azure Bastion: Connect to an Azure VM without accessing the Azure portal by using a shareable link – Wim Matthyssen