PowerShell has long been the standard tool for managing everything from Windows Server to Exchange to Office 365 and Azure resources and has more recently ventured into the cross-platform world with support for Linux and macOS via its PowerShell Core fork. With its robust scripting language, automation and remoting capabilities, PowerShell has proven to be invaluable and many IT Pros feel helpless without it. Therefore, it has become very important to ensure access to a PowerShell console wherever possible.
Using PowerShell in the browser is hardly something new, in fact, this functionality has been available for many years. Starting with Windows Server 2012, the Windows PowerShell Web Access feature allowed us to run PowerShell cmdlets and scripts on virtually any device, without needing to install additional software. That said, the PowerShell Web Access feature hasn't received much love since its original release, and while it’s still part of the Windows Server install, there’s hardly anything new to talk about.
So, why am I writing about it now, six years later? Azure Cloud Shell is one of the reasons. I’ve been meaning to do a comparison between the two, especially when it comes to managing things in the Office 365 world. After more announcements made at this year’s Ignite, I have a few more reasons to explore this topic further. Let’s dig right in.
PowerShell Web Access
As PowerShell Web Access (abbreviated as PSWA) has been available for years, I won't go into too much detail about installing and configuring the feature, you can find this information in the official documentation or on numerous blog posts. However, I will briefly talk about how you can use it, and what you can't do with it.
Cosmetics aside, once you log in to the PSWA page, you end up at a terminal window and you can start issuing cmdlets. Under the covers, PSWA uses remoting to connect to a given machine, which is why the Computer Name parameter is mandatory when logging in. Once connected, you have access to a fully-fledged PowerShell console, as indicated by the output of $PSVersionTable, and you can do more than run cmdlets. For example, you can invoke .NET classes and methods, such as the System.Environment class and its OSVersion property, showing the version/build of the current server. You can also call console applications such as
You get support for tab completion and execution history as well as most other PowerShell features you are familiar with. Finding and installing modules via the cmdlets exposed by the PowerShellGet module is one example, provided you are connected to a computer running a recent PowerShell version. You can quickly download the MSOnline module if it is not already present on the system. Once the module is installed, you can connect to Office 365 and start managing users.
While connectivity to Office 365 did work, you might have noticed that I used the -Credential switch for the Connect-MsolService cmdlet above. Doing so results in using a special OAuth flow, allowing me to connect via Modern authentication while at the same time bypassing the interactive login dialog. The reason is simple – since I’m running PowerShell in what’s effectively a terminal, there is no way for the interactive ADAL dialog to be shown. This, in turn, means that any module that requires you to do a fully interactive login will not work, and PowerShell will inform you accordingly with an error message. Connecting to services that accept $Credentials variable will work just fine though, for example the case of Exchange Online:
So in effect, I used my regular “connect to Office 365 script” in a browser session, and I’m now able to perform (almost) all the operations I’m used to
This is not the only limitation. For example, as this is a remote session and you are running in a different PowerShell host, there are no profiles available. It also means that you can't interactively remote to another machine using Enter-PSSession, for example in order to access a module installed on that machine. One alternative would be to relog to the PSWA gateway and choose the other machine instead. You can also use other methods, such as New-PSSession, Invoke-Command or the -ComputerName parameter, depending on the task.
Since you are bound to the terminal, copying and pasting information can be a drag, and so is viewing or editing files, and transferring files is an almost impossible task. Other “goodies” you might have become used to
Azure Cloud Shell
While Microsoft has barely touched PSWA in the past few years, they’ve put a lot of effort
Azure Cloud Shell can be accessed from multiple endpoints. It’s integrated into the Azure portal and the Azure mobile app, and also has a standalone website accessible via https://shell.azure.com. If you are accessing ACS via the Azure portal or the app and have already authenticated, you will be automatically logged in and granted access to Azure PowerShell for the current directory. If you are accessing it via the ACS webpage, you will have to authenticate and select the subscription/directory as part of the process. You can also select the type of shell, either Bash or PowerShell.
For the purpose of this article, we are of course interested in PowerShell. The below screenshot reveals some basic information about the environment, such as the version of PowerShell used, the OS on which it’s running, the fact that it’s running in a Hyper-V VM, the IP address of the machine. The PowerShell modules currently available are shown on the right, and additional modules can be added via Install-Module. In addition, some of the environmental variables are shown, which is something that will be important later on.
As this is a PowerShell Core instance running on Linux, there are some limitations. For example, even though I can download, install and import the MSOnline module just fine, I’m unable to use it to connect to Azure AD due to an underlying dependency on the ADAL binaries, as illustrated below:
The same goes for any other module that has a dependence on ADAL, unless it has been ported to .Net Core. Luckily, that’s exactly what Microsoft has done with the Azure modules, including a (preview) version of the Azure AD module you might have spotted in the output of Get-Module above. Therefore, we can use it instead of the MSOnline module in order to manage our Office 365 objects. In fact, there are a few methods you can use to connect to Azure AD, as shown below:
The first method is to simply use the Connect-AzureADService function, which will populate the AccountId and TenantId values based on the environmental variables and log you in automatically. Alternatively, you can run the Connect-AzureAD cmdlet without any parameters, which will trigger the device code OAuth flow, allowing you to complete the interactive authentication process from another endpoint and therefore bypass the limitations of PowerShell Core. Another method is to pass an Access token directly. Regardless of the method you choose, upon successful connection you can run all the familiar AzureAD cmdlets without any issues. This is in contrast with my earlier attempts to run Azure AD cmdlets on PowerShell Core, which resulted in various errors related to the parsing of JSON responses and whatnot.
When it comes to managing Exchange Online objects, PowerShell Core should do just fine, if you can get past the authentication part that is. If you are still using Basic auth, things will just work. If your account is protected by MFA or you have blocked legacy auth and must use the ADAL-enabled ExO module, you are out of luck, as the module is not yet ported to work on .NET Core and any attempt to use the Connect-ExOPSSession cmdlet will fail. But, you can still use various tricks, such as obtaining a token outside of the module and passing it:
Another nuisance of the Linux VM/PowerShell Core combo is also shown on the screenshot above, namely the rather annoying “ERROR_WSMAN_INVALID_SELECTORS” errors you often run into. This issue was first reported over a year ago by fellow MVP Michel de Rooij on Git
Leaving the Office 365 troubles aside, with ASC some of the annoyances with using PowerShell in the browser have been addressed. A basic syntax highlighter is available, and so is cross-session execution history. Instead of having to use command-line utilities such as vi or emacs, we get a built-in script editor. Transferring files in and out of the environment
The “end user” experience aside, ACS can present some administrative challenges. Being a part of the Azure portal, ACS is available anytime, on any device and from any location, which might not be something you desire. In a controlled access environment, restricting access to ACS can be done by blocking the endpoint on your network devices. If you are whitelisting locations from which users can authenticate, such as “named locations” for Conditional Access, you will have to whitelist entire Azure subnets, as the external IP used by the ACS environment is not static. ACS lacks the granularity of PSWA authorization rules and session configurations, or even basic branding controls outside of the Azure AD login branding.
So how practical is Azure Cloud Shell when it comes to performing your daily Office 365 tasks? If all you care about are Azure AD tasks, I’d say the experience is on par with running PowerShell on desktop. If you add Exchange tasks into the mix, things start to fall apart, unless you are still using basic auth. Almost all other Office 365 related modules have issues with running in an ACS environment, so if those are vital to you, I would advise waiting until a .NET Core version of the module is officially released by Microsoft.
Because of the problems with different modules, I would have to give ACS a 6/10, but that’s only when put in the context of Office 365 tasks. That score should change for the better in the coming months, as Microsoft continues developing the shell and ports more modules for PowerShell Core.
Summary and what’s next for Office 365 PowerShell in the browser
In this article, we explored the viability of using browser-based access to PowerShell environments, in the context of performing common Office 365 related tasks. Our first stop was PowerShell Web Access, a proven and reliable gateway allowing you to connect to a PowerShell session running on a machine in your on-premises or cloud environment. While PSWA hasn’t received any major updates in years and the interface can feel a bit clunky nowadays, it still gets the job done in most scenarios.
The other option we examined was Azure Cloud Shell, a PowerShell Core environment running on a Linux VM in Azure. While ACS offers a better experience overall, including file transfers and built-in editor, when it comes to Office 365 tasks it falls short due to the fact that most of the relevant modules are still not ported to .NET Core. Microsoft is working on that task and we already have a preview version of the Azure AD module available and pre-installed in the ACS environment. Moreover, we know that the ExO module is also being worked on. This is evident from the recent code changes made to the CreateExOPSSession script that detects whether the script is running in an ACS environment and updates the script parameters dynamically. A short core excerpt is shown below:
Yes, those are the exact same environmental variables we saw in the previous section, and this is how I know the module is being prepared for ACS. While the ExO module version doesn’t seem to be fully functional on ACS just yet, it should be available early next year. Until then, if you want to see it in action check out the following recording from Ignite 2018. Who knows, perhaps the team can go beyond what’s shown in the video, for example by integrating ACS as part of the Exchange Admin Center, where it can interoperate nicely with the existing “Show cmdlet logging” feature? Here’s hoping they do just that!
Vasil Michev is an Office Servers and Services MVP, specializing in Office 365. He's currently employed as a Cloud Technical Consultant, and in his free time he can be found helping others in the Office 365 community.