Using Azure Cloud Shell from PowerShell

Using Azure Cloud Shell from PowerShell

Azure Cloud Shell is a browser-based shell for managing Azure resources using your favourite shell, Bash or PowerShell. Cloud Shell is typically used from Azure Portal. It provides an easy access to Azure CLI, Azure PowerShell and Azure AD PowerShell.

In this blog, I’ll introduce a new way to access Cloud Shell from PowerShell (requires AADInternals v0.4.3 or newer).

What Azure Cloud Shell

As per Microsoft documentation:

Azure Cloud Shell is an interactive, authenticated, browser-accessible shell for managing Azure resources. It provides the flexibility of choosing the shell experience that best suits the way you work, either Bash or PowerShell.

Cloud Shell can be accessed in four different ways: Using a direct link (shell.azure.com), from Azure portal, from docs.microsoft.com code snippets, and now from PowerShell with AADInternals.

Typically, the Cloud Shell is used from the Azure portal: Azure Portal

The nicest feature of the Cloud Shell is that it comes with pre-installed PowerShell and CLI tools for managing Azure.

For instance, listing the available PowerShell modules shows that we have all we need to manage Azure and Azure AD.

PS /home/admin> Get-Module -ListAvailable
    Directory: /usr/local/share/powershell/Modules

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Script     4.7.0                 Az                                  Core,Desk
Script     1.9.4                 Az.Accounts                         Core,Desk {Disable-AzDataCollection, Disable-AzContex…
Script     1.1.1                 Az.Advisor                          Core,Desk {Get-AzAdvisorRecommendation, Enable-AzAdvi…
Script     1.3.0                 Az.Aks                              Core,Desk {Get-AzAksCluster, New-AzAksCluster, Remove…
Script     1.1.4                 Az.AnalysisServices                 Core,Desk {Resume-AzAnalysisServicesServer, Suspend-A…
Script     2.1.0                 Az.ApiManagement                    Core,Desk {Add-AzApiManagementApiToGateway, Add-AzApi…
Script     1.1.0                 Az.ApplicationInsights              Core,Desk {Get-AzApplicationInsights, New-AzApplicati…
Script     1.4.0                 Az.Automation                       Core,Desk {Get-AzAutomationHybridWorkerGroup, Remove-…
Script     3.1.0                 Az.Batch                            Core,Desk {Remove-AzBatchAccount, Get-AzBatchAccount,…
Script     1.0.3                 Az.Billing                          Core,Desk {Get-AzBillingInvoice, Get-AzBillingPeriod,…
Script     1.4.3                 Az.Cdn                              Core,Desk {Get-AzCdnProfile, Get-AzCdnProfileSsoUrl, …
Script     1.6.0                 Az.CognitiveServices                Core,Desk {Get-AzCognitiveServicesAccount, Get-AzCogn…
Script     4.4.0                 Az.Compute                          Core,Desk {Remove-AzAvailabilitySet, Get-AzAvailabili…
Script     1.0.3                 Az.ContainerInstance                Core,Desk {New-AzContainerGroup, Get-AzContainerGroup…
Script     1.1.1                 Az.ContainerRegistry                Core,Desk {New-AzContainerRegistry, Get-AzContainerRe…
Script     1.1.0                 Az.DataBoxEdge                      Core,Desk {Get-AzDataBoxEdgeJob, Get-AzDataBoxEdgeDev…
Script     1.10.1                Az.DataFactory                      Core,Desk {Set-AzDataFactoryV2, Update-AzDataFactoryV…
Script     1.0.2                 Az.DataLakeAnalytics                Core,Desk {Get-AzDataLakeAnalyticsDataSource, New-AzD…
Script     1.2.8                 Az.DataLakeStore                    Core,Desk {Get-AzDataLakeStoreTrustedIdProvider, Remo…
Script     1.0.0                 Az.DataShare                        Core,Desk {New-AzDataShareAccount, Get-AzDataShareAcc…
Script     1.1.0                 Az.DeploymentManager                Core,Desk {Get-AzDeploymentManagerArtifactSource, New…
Script     1.0.0                 Az.DesktopVirtualization            Core,Desk {Disconnect-AzWvdUserSession, Get-AzWvdAppl…
Script     1.0.2                 Az.DevTestLabs                      Core,Desk {Get-AzDtlAllowedVMSizesPolicy, Get-AzDtlAu…
Script     1.1.2                 Az.Dns                              Core,Desk {Get-AzDnsRecordSet, New-AzDnsRecordConfig,…
Script     1.3.0                 Az.EventGrid                        Core,Desk {New-AzEventGridTopic, Get-AzEventGridTopic…
Script     1.6.0                 Az.EventHub                         Core,Desk {New-AzEventHubNamespace, Get-AzEventHubNam…
Script     1.6.1                 Az.FrontDoor                        Core,Desk {New-AzFrontDoor, Get-AzFrontDoor, Set-AzFr…
Script     1.0.2                 Az.Functions                        Core,Desk {Get-AzFunctionApp, Get-AzFunctionAppAvaila…
Script     0.10.8                Az.GuestConfiguration               Core,Desk {Get-AzVMGuestPolicyStatus, Get-AzVMGuestPo…
Script     3.6.0                 Az.HDInsight                        Core,Desk {Get-AzHDInsightJob, New-AzHDInsightSqoopJo…
Script     1.1.0                 Az.HealthcareApis                   Core,Desk {New-AzHealthcareApisService, Remove-AzHeal…
Script     2.5.0                 Az.IotHub                           Core,Desk {Add-AzIotHubKey, Get-AzIotHubEventHubConsu…
Script     2.2.0                 Az.KeyVault                         Core,Desk {Add-AzKeyVaultCertificate, Update-AzKeyVau…
Script     1.0.0                 Az.Kusto                            Core,Desk {Add-AzKustoClusterLanguageExtension, Add-A…
Script     1.3.2                 Az.LogicApp                         Core,Desk {Get-AzIntegrationAccountAgreement, Get-AzI…
Script     1.1.3                 Az.MachineLearning                  Core,Desk {Move-AzMlCommitmentAssociation, Get-AzMlCo…
Script     1.1.0                 Az.Maintenance                      Core,Desk {Get-AzApplyUpdate, Get-AzConfigurationAssi…
Script     1.1.0                 Az.ManagedServices                  Core,Desk {Get-AzManagedServicesAssignment, New-AzMan…
Script     1.0.2                 Az.MarketplaceOrdering              Core,Desk {Get-AzMarketplaceTerms, Set-AzMarketplaceT…
Script     1.1.1                 Az.Media                            Core,Desk {Sync-AzMediaServiceStorageKey, Set-AzMedia…
Script     2.1.0                 Az.Monitor                          Core,Desk {Get-AzMetricDefinition, Get-AzMetric, Remo…
Script     3.4.0                 Az.Network                          Core,Desk {Add-AzApplicationGatewayAuthenticationCert…
Script     1.1.1                 Az.NotificationHubs                 Core,Desk {Get-AzNotificationHub, Get-AzNotificationH…
Script     2.3.0                 Az.OperationalInsights              Core,Desk {New-AzOperationalInsightsAzureActivityLogD…
Script     1.3.1                 Az.PolicyInsights                   Core,Desk {Get-AzPolicyEvent, Get-AzPolicyState, Get-…
Script     1.1.2                 Az.PowerBIEmbedded                  Core,Desk {Remove-AzPowerBIWorkspaceCollection, Get-A…
Script     1.0.3                 Az.PrivateDns                       Core,Desk {Get-AzPrivateDnsZone, Remove-AzPrivateDnsZ…
Script     2.12.1                Az.RecoveryServices                 Core,Desk {Get-AzRecoveryServicesBackupProperty, Get-…
Script     1.2.1                 Az.RedisCache                       Core,Desk {Remove-AzRedisCachePatchSchedule, New-AzRe…
Script     1.0.3                 Az.Relay                            Core,Desk {New-AzRelayNamespace, Get-AzRelayNamespace…
Script     2.5.1                 Az.Resources                        Core,Desk {Get-AzProviderOperation, Remove-AzRoleAssi…
Script     1.4.1                 Az.ServiceBus                       Core,Desk {New-AzServiceBusNamespace, Get-AzServiceBu…
Script     2.2.0                 Az.ServiceFabric                    Core,Desk {Add-AzServiceFabricClientCertificate, Add-…
Script     1.2.0                 Az.SignalR                          Core,Desk {New-AzSignalR, Get-AzSignalR, Get-AzSignal…
Script     2.10.0                Az.Sql                              Core,Desk {Get-AzSqlDatabaseTransparentDataEncryption…
Script     1.1.0                 Az.SqlVirtualMachine                Core,Desk {New-AzSqlVM, Get-AzSqlVM, Update-AzSqlVM, …
Script     2.6.0                 Az.Storage                          Core,Desk {Get-AzStorageAccount, Get-AzStorageAccount…
Script     1.3.0                 Az.StorageSync                      Core,Desk {Invoke-AzStorageSyncCompatibilityCheck, Ne…
Script     1.0.1                 Az.StreamAnalytics                  Core,Desk {Get-AzStreamAnalyticsFunction, Get-AzStrea…
Script     1.0.0                 Az.Support                          Core,Desk {Get-AzSupportService, Get-AzSupportProblem…
Script     1.0.4                 Az.TrafficManager                   Core,Desk {Add-AzTrafficManagerCustomHeaderToEndpoint…
Script     1.11.0                Az.Websites                         Core,Desk {Get-AzAppServicePlan, Set-AzAppServicePlan…
Script     0.0.0.10              AzureAD.Standard.Preview            Desk      {Set-AzureADTenantDetail, Set-AzureADApplic…
Script     0.9.3                 AzurePSDrive                        Desk
Script     17.0.4716…            EXOPSSessionConnector               Desk      Connect-EXOPSSession
Binary     0.1.1                 Microsoft.PowerShell.UnixCompleters Core      {Import-UnixCompleters, Remove-UnixComplete…
Manifest   1.0.840               MicrosoftPowerBIMgmt                Desk
Binary     1.0.840               MicrosoftPowerBIMgmt.Admin          Desk      {Add-PowerBIEncryptionKey, Get-PowerBIEncry…
Binary     1.0.840               MicrosoftPowerBIMgmt.Capacities     Desk      Get-PowerBICapacity
Binary     1.0.840               MicrosoftPowerBIMgmt.Data           Desk      {Add-PowerBIDataset, Set-PowerBITable, New-…
Binary     1.0.840               MicrosoftPowerBIMgmt.Profile        Desk      {Connect-PowerBIServiceAccount, Disconnect-…
Binary     1.0.840               MicrosoftPowerBIMgmt.Reports        Desk      {Get-PowerBIReport, New-PowerBIReport, Expo…
Binary     1.0.840               MicrosoftPowerBIMgmt.Workspaces     Desk      {Get-PowerBIWorkspace, Get-PowerBIWorkspace…
Binary     1.1.4                 MicrosoftTeams                      Core,Desk {Add-TeamUser, Connect-MicrosoftTeams, Disc…
Script     0.9.3                 PSCloudShellUtility                 Desk      {Enter-AzVM, Get-AzCommand, Invoke-AzVMComm…
Binary     0.8.1                 SHiPS                               Desk
Script     21.1.18226            SqlServer                           Desk      {Add-RoleMember, Add-SqlAvailabilityDatabas…

    Directory: /opt/microsoft/powershell/7/Modules

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Manifest   1.2.5                 Microsoft.PowerShell.Archive        Desk      {Compress-Archive, Expand-Archive}
Manifest   7.0.0.0               Microsoft.PowerShell.Host           Core      {Start-Transcript, Stop-Transcript}
Manifest   7.0.0.0               Microsoft.PowerShell.Management     Core      {Add-Content, Clear-Content, Clear-ItemProp…
Manifest   7.0.0.0               Microsoft.PowerShell.Security       Core      {Get-Credential, Get-ExecutionPolicy, Set-E…
Manifest   7.0.0.0               Microsoft.PowerShell.Utility        Core      {Export-Alias, Get-Alias, Import-Alias, New…
Script     1.4.7                 PackageManagement                   Desk      {Find-Package, Get-Package, Get-PackageProv…
Script     2.2.4.1               PowerShellGet                       Desk      {Find-Command, Find-DSCResource, Find-Modul…
Script     2.0.5                 PSDesiredStateConfiguration         Core      {Configuration, New-DscChecksum, Get-DscRes…
Script     2.0.2                 PSReadLine                          Desk      {Get-PSReadLineKeyHandler, Set-PSReadLineKe…
Binary     2.0.3                 ThreadJob                           Desk      Start-ThreadJob

It is even possible to install AADInternals to Cloud Shell! However, as Cloud Shell is running on Linux, only .Net Core is supported. So everything will not work.

Using Cloud Shell from PowerShell

Technically, the Cloud Shell is nothing but a WebSocket connection to terminal session of a Linux box in Azure.

Technical details

The technical process to connect to Cloud Shell is as follows.

Step one

First, a HTTP request (PUT) is sent to:

https://management.azure.com/providers/Microsoft.Portal/consoles/default?api-version=2020-04-01-preview

The payload of the request is:

{"properties":{"osType":"linux"}}

The response includes an url for the gateway.

{
  "properties": {
    "osType": "Linux",
    "provisioningState": "Succeeded",
    "uri": "https://gateway12.westeurope.console.azure.com:443/n/cc-20a66344/cc-20a66344"
  }
}

Step two

Next, a HTTP request (POST) is sent to the gateway url with the size information (rows and columns) and the shell type (bash or pwsh):

https://gateway12.westeurope.console.azure.com/n/cc-20a66344/cc-20a66344/terminals?cols=124&rows=13&version=2019-01-01&shell=pwsh

The response includes the url for the terminal WebSocket.

{
	"id": "0ca733551cd94ce83f8d6a1b023ff8ef",
	"socketUri": "wss://gateway12.westeurope.console.azure.com/n/cc-20a66344/cc-20a66344/terminals/0ca733551cd94ce83f8d6a1b023ff8ef",
	"idleTimeout": "20",
	"tokenUpdated": true,
	"rootDirectory": "/home/admin"
}

Step three

Next, a HTTP request (POST) is sent to the gateway for authorization:

https://gateway12.westeurope.console.azure.com/n/cc-20a66344/cc-20a66344/authorize

The response includes the authorization token.

{"token":"KtkU1c9zXEh1jidHf6xYskuZL5N4WujFsiw043VDEm0mq7MjBnbOKJR92nmoWazUL4yFEcm4PRRq4r5KJag"}

Step four

The final step is make a WebSocket connection to the gateway address:

wss://gateway12.westeurope.console.azure.com/n/cc-20a66344/cc-20a66344/terminals/0ca733551cd94ce83f8d6a1b023ff8ef

The authorization token must be included in a cookie:

Cookie: auth-token=KtkU1c9zXEh1jidHf6xYskuZL5N4WujFsiw043VDEm0mq7MjBnbOKJR92nmoWazUL4yFEcm4PRRq4r5KJag

After the connection is made, all keystrokes from the (local) PowerShell are sent through the WebSocket to Azure. Also everything sent from the Azure through the WebSocket are printed to console.

The output from the Azure are VT100 based control character sequences. Luckily, since around 2018, PowerShell console supports VT100! So, all I had to do was to pipe things directly between PowerShell console and Cloud Shell.

Making the connection

Connecting to Cloud Shell with AADInternals is pretty straight forward:

# Get access token 

Get-AADIntAccessTokenForCloudShell -SaveToCache

# Start the Cloud Shell (PowerShell)

Start-AADIntCloudShell

Cloud Shell

To start a Bash shell instead:

# Start the Cloud Shell (Bash)

Start-AADIntCloudShell -Shell Bash

Cloud Shell

To exit from the Cloud Shell, type exit

You can also move between PowerShell and Bash in Cloud Shell. To start a bash shell while in PowerShell, type bash. To start PowerShell while in Bash, type pwsh.

References

Dr Nestori Syynimaa (@DrAzureAD) avatar
About Dr Nestori Syynimaa (@DrAzureAD)
Dr Syynimaa works as Principal Identity Security Researcher at Microsoft Security Research.
Before his security researcher career, Dr Syynimaa worked as a CIO, consultant, trainer, and university lecturer for over 20 years. He is a regular speaker in scientific and professional conferences related to Microsoft 365 and Entra ID (Azure AD) security.

Before joining Microsoft, Dr Syynimaa was Microsoft MVP in security category and Microsoft Most Valuable Security Researcher (MVR).