Welcome to the fourth article of the series on Shareable Links for Azure Bastion. As promised in the previous article, I will try to automate deleting a shareable link for Azure Bastion. In this article, I intend to build a PowerShell function to delete a shareable Azure Bastion link. Let's see how we can do it.
6 posts tagged with "Azure Bastion"
View All TagsShareable Link for Azure Bastion - Part 3
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.
Shareable Link for Azure Bastion - Part 2
Great to see you again! In the previous article, we tried to create a resource group for our lab environment. From now on, I will jump right into my script to create a lab environment. I will explain the script line by line. You can also find the script in end of the article and in my GitHub repository.
Shareable Link for Azure Bastion - Part 1
Hello Friends, I believe that you have probably heard about the Azure Bastion. It is a service that provides secure and seamless RDP/SSH connectivity to your VMs directly in the Azure portal over SSL. It removes the need to implement inbound ports for RDP/SSH and the need to manage jump boxes. You can connect to your VM using the Azure portal or Azure CLI.
I will try to automate creating a shareable link for Azure Bastion Hosts in this article series. I will use Azure PowerShell to create a shareable link(s) for Azure Bastion Host(s). Nothing stops you from generating a shareable link for Azure Bastion using the Azure Portal. This article series intends to automate provisioning a shareable link for Azure Bastion.
Manage Azure Bastion Sessions with PowerShell - Part 2
Hello Folks, Welcome to the second part of the series. Previously, we discussed the fundamentals of session monitoring and management for Azure Bastion and how to get the active session and terminate the session using the REST API. In this article, we will talk about the PowerShell Function that we will use to manage the sessions. Let's get into it.
🌱Scaffolding the PowerShell Function
The Function name will be Remove-AzBastionActiveSessions
and it will have the following parameters:
- BastionHostNames (Array)
- VMNames (Array)
- SubscriptionId (String)
I tried to keep the parameters as simple as possible. The Function will have the following logic:
- Iterates through the Bastion Hosts
- Gets the active sessions for each Bastion Host
- Filters the sessions based on the VM Names
- Terminates the sessions
💻 The PowerShell Function
Function Remove-AzBastionActiveSessions {
<#
.SYNOPSIS
Author: Hasan Gural - Azure VMP
Version: BETA
.DESCRIPTION
There is no way for terminating the active sessions for the Bastion Host in the Azure PowerShell module. This function will hit the REST API directly to terminate the active sessions.
.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
Remove-AzBastionActiveSessions -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 for removing the shareable links. Existing links will remain intact.
#>
[CmdletBinding()]
param (
[Parameter()]
[array]
$VMNames,
[Parameter()]
[array]
$BastionNames,
[Parameter()]
$SubscriptionId
)
$links = @() # Array to store deleted 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] - ---------------------------------"
$uri = "https://management.azure.com/subscriptions/$($SubscriptionId)/resourceGroups/$($ResourceGroupName)/providers/Microsoft.Network/bastionHosts/$($Name)/getActiveSessions?api-version=2022-07-01"
$getOperationActiveSessions = (Invoke-WebRequest -Method Post -Uri $uri -Headers $header).Headers.Location[0]
Start-Sleep -Seconds 5 # Wait for retrieving the active sessions.
$getActiveSession = (Invoke-WebRequest -Method Get -Uri $getOperationActiveSessions -Headers $header).Content | ConvertFrom-Json
if ($getActiveSession) {
ForEach ($vm in $VMNames) {
$getVM = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $vm -ErrorAction SilentlyContinue
$vmSessions = $getActiveSession | Where-Object { $_.targetHostName -eq $vm }
ForEach ($session in $vmSessions) {
$taskCount = 1 # Task counter
Write-Output "[TASK 1.$($taskCount)] - Retrieving the active sessions for $vm. Please wait."
if ($getVM.ProvisioningState -eq "Succeeded") {
if ($getVM.Name -eq $session.targetHostName) {
$requestBody = @{
"sessionIds" = @($session.sessionId)
}
$uri = "https://management.azure.com/subscriptions/$($SubscriptionId)/resourceGroups/$($ResourceGroupName)/providers/Microsoft.Network/bastionHosts/$($Name)/disconnectActiveSessions?api-version=2022-07-01"
$response = Invoke-WebRequest -Method Post -Uri $uri -Headers $header -Body (ConvertTo-Json $requestBody -Depth 10)
Write-Output "[TASK 1.$($taskCount)] - Terminating the active session for $vm. Please wait. This may take a while."
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."
}
else {
Write-Output "[Error] - Active Session does not exist for the Virtual Machine: $vm"
continue
}
}
else {
Write-Output "[Error] - Virtual Machine $vm does not exist. Please check the name and try again."
continue
}
}
}
}
else {
Write-Output "[Error] - There is no active session for the Bastion Host: $bastion"
}
}
else {
Write-Output "[Error] - Bastion Host $bastion does not exist. Please check the name and try again."
continue
}
}
}
🔌 Executing the Function
The Function will be executed as follows:
$params = @{
VMNames = @("vm-01", "vm-02") # Name of Virtual Machines that you want to terminate the sessions
BastionNames = @("bastion-vnt-0001") # Name of the Bastion Hosts
SubscriptionId = $subscriptionId
}
Remove-AzBastionActiveSessions @params
✨ Example Output
In the following example, we will terminate the active sessions for the Bastion Host bastion-vnt-0001
and the Virtual Machines vm-01
and vm-02
. See the output below for active sessions before and after the execution of the Function.
I have executed the PowerShell Function below and you can see that it terminated the active sessions.
🚀 Conclusion
Imagine that you have a Bastion Host(s) that has multiple active sessions and you want to terminate them. You can use the PowerShell Function that I have shared in this article. You can also schedule this function to run periodically to terminate the active sessions. This will help you avoid running out of the Bastion Hosts.
Thanks for reading this through. For more improvements, please let me know. I will be happy to hear your feedback.
Manage Azure Bastion Sessions with PowerShell - Part 1
Hello Friends, Happy to see you again. In this article, I will briefly talk about Azure Bastion Session Management. In the first part of the series, I will go over the basics of session monitoring and management for Azure Bastion. Let's get into it.
💬What is Bastion's Session Management?
You might want to manage the sessions if you're using Azure Bastion. For example, you wish to terminate the session or view the session details and so forth. Session Management is a feature that allows you to manage active sessions or terminate the sessions. If you're already using Azure Bastion, you should be sending the logs to Log Analytics. If you're not, please do that as soon as possible. Log analytics can help to see the session details and Bastion Audit Logs. The Diagnostics Logs can be sent to Log Analytics and Storage Accounts so that you can view the session details.
🌱How to Manage Azure Bastion Sessions?
It is evident that you can manage the sessions from the Azure Portal, but key point is that we would like to manage the sessions from PowerShell. In order to do that, we will interact with the Azure Bastion REST API. When you skim through the Azure Bastion REST API, you will see that there are two endpoints. One is for the getActiveSessions
and the other one is for the disconnectActiveSessions
.
🧑💻 Quick insight into the REST API endpoints
🔗 getActiveSessions
The GetActiveSessions
endpoint is used to get the active sessions. It returns the list of active sessions. The endpoint is as follows:
Method: POST
"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/bastionHosts/{bastionHostName}/getActiveSessions?api-version=2022-07-01"
When you send a request to the endpoint, you will probably get the following response:
{
"value": [
{
"sessionId": "sessionId",
"startTime": "2019-1-1T12:00:00.0000Z",
"targetSubscriptionId": "subid",
"resourceType": "VM",
"targetHostName": "vm01",
"targetResourceGroup": "rg1",
"userName": "user",
"targetIpAddress": "1.1.1.1",
"protocol": "SSH",
"targetResourceId": "/subscriptions/subid/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm01",
"sessionDurationInMins": 0
}
]
}
The result of the GetActiveSessions
endpoint is a list of active sessions. The sessionId
is the unique identifier of the session. Generally, the endpoint returns responses 200
and 202
. If the response is 202
, it means that the request is accepted, and the session details will be returned later. Bear in mind that you will need to send the request again to get the session details.
🔗 disconnectActiveSessions
Method: POST
"POST https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/bastionHosts/{bastionHostName}/disconnectActiveSessions?api-version=2022-07-01"
Once you get the session details, you can terminate the session by sending a request to the disconnectActiveSessions
endpoint. When you send a request to the endpoint, you must send the sessionIds
as a request body. The request body must be in the following format:
sessionIds: [
"session1",
"session2",
"session3"
]
Looks like Azure Bastion REST API is pretty straightforward for newcomers. The tricky part is that you will need to send the request again to get the session details. I look forward to finishing the PowerShell part in the following article. We are getting closer to the end of the article. Stay tuned for the next part.