Skip to main content

Shareable Link for Azure Bastion - Part 3

· 6 min read
Hasan Gural

The time has come to build PowerShell Functions for the feature of Shareable Links for Azure Bastion. In this article, I will try to build a PowerShell function to create a shareable link for Azure Bastion. First, there is no way to create Bastion Shareable Links using Azure PowerShell Cmdlets. That's why we will try to come up with a be-spoke solution. At the end of the article series, we will have a couple of PowerShell Functions that can create, update, delete, and get shareable links for Azure Bastion.

Creating a shareable link for Azure Bastion on Azure Portal is pretty straightforward. Let's see how we can do it with Azure Portal and understand what we are trying to automate.

  1. Go to Azure Portal and select your Azure Bastion resource.
  2. On the feft side of the menu, select Shareable Links.
  3. Click on Add button.
  4. Fill out the form and click on Create button

image

Once you click on Create button, you will see a new shareable link created. Just wanted to mention that you can create shareable links for multiple virtual machines. I have made a shareable link for a single virtual machine in this example.

caution

You can only create a shareable link for virtual machines or scalet sets that are in the same virtual network as the Azure Bastion resource. You can't create a shareable link for a virtual machine that is in a different virtual network and on-premises resources.

image

Afterward, you can start using the shareable link. You can share the link with your colleagues, who can access the virtual machine through Azure Bastion without any authentication. That's the beauty of shareable links for Azure Bastion.

image

If you see the example above, that's the authentication page for Shareable Link. You can see that there is no authentication required. Fill out the form, click the Connect button, and you're in! The same experience that you will see regardless you have authenticated or not.

Let's dig into PowerShell and understand its capabilities. The PowerShell Function will create a shareable link(s) for Azure Bastion(s). It looks a little bit complicated, but it's not. Let's see how we can do it. The script supports multiple Azure Bastion Hosts and multiple virtual machines. You can run the script multiple times to add more virtual machines and Azure Bastion Hosts to the shareable link. Existing links will remain intact.

Function New-AzBastionShareAbleLink {
<#
.SYNOPSIS
This function will create a shareable link for the Bastion Host
Author: Hasan Gural - Azure VMP
Version: 1.0.0-beta
.DESCRIPTION
There is no way to create a shareable link for the Bastion Host in the Azure PowerShell module. This function will hit the REST API directly to create the shareable link.
.NOTES
This function won't enable the shareable link feature for the Bastion Host. This needs to be done manually or see previous article on how to do this.
.EXAMPLE
New-AzBastionShareAbleLink -VMNames @("vm-01", "vm-03", "vm-02") -BastionNames @("bastion-vnt-0001","bastion-vnt-0003") -SubscriptionId $subscriptionId
Function will support multiple VMs and Bastion Hosts. Just pass in the names of the VMs and Bastion Hosts and the subscription ID.
You can run the script multiple times to add more VMs and Bastion Hosts to the shareable link. Existing links will remain intact.
#>


[CmdletBinding()]
param (
[Parameter()]
[array]
$VMNames,

[Parameter()]
[array]
$BastionNames,

[Parameter()]
$SubscriptionId
)

$links = @() # Array to store the links

$header = @{

"Content-Type" = "application/json"
Authorization = ("Bearer " + (Get-AzAccessToken).Token)
}

ForEach ($bastion in $BastionNames) {

$getBastion = Get-AzBastion -ErrorAction SilentlyContinue | Where-Object {$_.Name -eq $bastion}

if ($getBastion.ProvisioningState -eq "Succeeded") {

$ResourceGroupName = $getBastion.ResourceGroupName
$Location = $getBastion.Location
$SubscriptionId = $getBastion.Id.Split('/')[2]
$Name = $getBastion.Name

Write-Output "[INFO] - ---------------------------------"
Write-Output "[INFO] - Bastion Host Name: $bastion "
Write-Output "[INFO] - Resource Group: $ResourceGroupName"
Write-Output "[INFO] - Subscription: $SubscriptionId"
Write-Output "[INFO] - Location: $Location"
Write-Output "[INFO] - ---------------------------------"

Foreach ($vm in $VMNames) {

$getVM = Get-AzVM -ErrorAction SilentlyContinue | Where-Object {$_.Name -eq $vm}

if ($getVM.ProvisioningState -eq "Succeeded") {

$requestBody = @{

"vms" = @(
@{
"vm" = @{
"id" = $getVM.Id
}
}
)

}

$uri = "https://management.azure.com/subscriptions/$($SubscriptionId)/resourceGroups/$($ResourceGroupName)/providers/Microsoft.Network/bastionHosts/$($Name)/createShareableLinks?api-version=2022-07-01"

$response = Invoke-WebRequest -Method Post -Uri $uri -Headers $header -Body (ConvertTo-Json $requestBody -Depth 10)
Start-Sleep -Seconds 5 # Wait for the link to be created. This is to avoid the error "The link is not ready yet. Please try again later."

if($response.StatusCode -eq 202) {

Write-Output "[TASK 1.0] - Shareable Link is created for $vm. Please wait for retrieving the link."

$uri = "https://management.azure.com/subscriptions/$($SubscriptionId)/resourceGroups/$($ResourceGroupName)/providers/Microsoft.Network/bastionHosts/$($Name)/GetShareableLinks?api-version=2022-07-01"

$getBastionLink = Invoke-RestMethod -Method Post -Uri $uri -Headers $header -Body (ConvertTo-Json $requestBody -Depth 10)


}

$links += [PSCustomObject]@{

"VMName" = $vm
"Bastion" = $bastion
"ResourceGroup" = $ResourceGroupName
"Link" = $getBastionLink.value.bsl
"Created Date" = $getBastionLink.value.createdAt

}

Write-Output "[TASK 1.1] - Shareable Link has added for the Virtual Machine: $vm"
}

else {

Write-Output "[Error] - Virtual Machine $vm does not exist. Please check the name and try again."
continue

}

}

}
else {

Write-Output "[Error] - Bastion Host $bastion does not exist. Please check the name and try again."
continue

}
}

return $links | Format-Table -AutoSize

}

⚓Run the PowerShell Function

This a big fascinating moment! Let's run the PowerShell Function and see how it works. When you load the PowerShell Function in your PowerShell session, you can see the parameters that you need to pass in. You must pass in the virtual machines' names and Azure Bastion Hosts. You also need to pass in the subscription ID.


New-AzBastionShareAbleLink -VMNames @("vm-01", "vm-02") -BastionNames @("bastion-vnt-0001") -SubscriptionId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Example output of the PowerShell Function:

image

It is stunning, isn't it? You can see that the PowerShell Function has created a shareable link for the virtual machine vm-01 and vm-02 and added it to the Azure Bastion Host bastion-vnt-0001. You can see the link and the date that the link was created. You can copy the link and share it with your colleagues. They can access the virtual machine(s) without authenticating to Azure Portal.

The same script can be used to add more VMs and Bastion Hosts to the shareable link. You can run the script multiple times to add more VMs and Bastion Hosts to the shareable link. Existing links will remain intact. Imagine that you have 100 VMs and 10 Bastion Hosts. You can create a shareable link for all of them in a few minutes.

I will try to add more features to the PowerShell Function in the future. I am thinking of adding the ability to remove the shareable link. If you have any suggestions, please let me know. Stay tuned for more articles.