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:
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
To start a Bash shell instead:
# Start the Cloud Shell (Bash)
Start-AADIntCloudShell -Shell Bash
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
- Microsoft: Overview of Azure Cloud Shell
- Microsoft: Console Virtual Terminal Sequences