Finding your way around the AWS Tools for PowerShell
Tags: aws, powershell
Published: 2022-02-17 00:59:43

I’ve been writing and presenting on the [AWS Tools for PowerShell](https://aws.amazon.com/powershell/) recently and, out of curiosity, decided to take a look at how many cmdlets the tools now support. Back when we shipped version 1, in 2013, the (then single) module contained around 500 cmdlets spanning 20 or so services.

Having maintained and enhanced the tools for several years, and seen them grow to support the expanding set of services for AWS, I was however somewhat unprepared for the scale of what I found. On a new EC2 instance, running Windows Server 2019 with the monolithic [AWSPowerShell module](https://www.powershellgallery.com/packages/AWSPowerShell/) pre-installed (like all Windows images provided by the EC2 team), `Get-Command` reported over 11000 cmdlets!

When I moved on from being the lead developer a couple years back, the tools had grown to over 5000 cmdlets, and expansion has obviously continued. Back then, we broke our ability to publish the monolithic modules (AWSPowerShell and [AWSPowerShell.NetCore](https://www.powershellgallery.com/packages/AWSPowerShell.NetCore/)) to the PowerShell Gallery a couple times, as we’d stumbled over a previously undocumented limit on the number of cmdlet names you could include in the module manifest. In order to publish, we had to remove the cmdlet names from the module manifests, which is why tab-completion of cmdlet names failed periodically every time we broke through the limit.

Although the PowerShell team did us a favor and raised the limit a few times, allowing us to reinstate the exported names, it was clear this wasn’t going to be a workable approach going forward. The sheer size of the monolithic modules was why the AWS team refactored to per-service modules, known as [AWS.Tools.*](https://www.powershellgallery.com/packages?q=AWS.Tools.*), on the gallery. The per-service modules load faster, always have tab completion for cmdlet names, and offer the additional benefit of not having to have all 11000+ cmdlets installed if you're only working with a handful of services.

All editions of the tools (AWSPowerShell, AWSPowerShell.NetCore, and AWS.Tools.*) contain the same overall set of cmdlets – it’s just a packaging variation. The monolithic modules are kept around for backwards compatibility as there are scripts out there that import the modules from their pre-installed location on the EC2 instances.

So, this all begs a question – given over 11000 cmdlets spanning 200 services, how do you find your way around? How do you locate the cmdlets for a given service and, within that service, how do you find the cmdlet you need for a given service API? (Pretty much all of the cmdlets map 1:1 with AWS service APIs.) Let’s take a look.

## The AWS cmdlet naming convention

When we originally created the tools, we had one module but needed to find a way to distinguish cmdlets between different services that used the same underlying API name. For example, several services have an API named `DescribeInstances` (EC2 being one such service). This would ordinarily map to a cmdlet name like `Get-Instance`, but only one service could then use this in our single module, unless we add a parameter to distinguish the service. That’s not the route we took. Instead, we chose to prefix the noun portion of the cmdlet name with a short 2-5 letter "tag" identifying the parent service – so `Get-EC2Instance`, `Get-GMLInstance` (GameLift), and `Get-OPSInstance` (OpsWorks), for example.

The prefix tags for some services are obvious – S3, EC2, ECS, etc., while others are less so. Interestingly, when we started to look at refactoring to per-service modules and asked our user base about potentially dropping the convention we got a 50/50 split between keeping and dropping the prefix. Ensuring backwards compatibility also played a large part in our decision making to keep the prefix.

The prefix tags allow us to isolate cmdlets for a service, but how to find the tag used for a service? The cmdlets contain a custom version cmdlet, `Get-AWSPowerShellVersion` (I don’t recall why we added this now, but it has its uses). When invoked with the `-ListServiceVersionInfo` parameter, one of the data items it outputs is the noun prefix:

![Listing service prefixes with Get-AWSPowerShellVersion](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nal1dalp3ck35e1bicku.png)

I have the AWS.Tools modules installed, so you can also see the corresponding per-service module. If you’re using the monolithic versions, you’ll see AWSPowerShell or AWSPowerShell.NetCore in that third column. For the AWS.Tools edition, the version cmdlet reports the prefix tags of all supported services, even if you don’t have the module for a particular service installed.

## Finding cmdlets for a service

Now that we know how to identify the prefix tag for a service, how do you list the cmdlets for that service? For the AWS.Tools modules, `Get-Command` will suffice if you have the corresponding module installed (for example, `Get-Command -Module AWS.Tools.EC2`). This isn’t so clear-cut with the monolithic modules however, and only works with the per-service modules if the module is installed.

Back in the mists of time we added the cmdlet `Get-AWSCmdletName` to help with discovery. This cmdlet takes advantage of additional metadata that we compile into every cmdlet, enabling users to slice-and-dice the set of cmdlets based on service, API, and AWS CLI command.

To find the set of cmdlets for a service, use the `-Service` parameter. This nets you the set of cmdlets, and corresponding APIs (as well as service name and module name, not shown in this example), for the specified service. Again, with the AWS.Tools modules, this works even if you don’t have the corresponding service module installed:

![Listing cmdlets by service prefix](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9wopb3jt9hwb4edk3eem.png)

_Note: all the images in this post use a Windows command line prompt, however all these commands can be used on Linux and macOS too. For those of you that might be unaware, PowerShell is no longer tied to Windows!_

If you don’t know the service tag, you can use all or part of the service name to get the same kind of result. However, as some services use similar words (“elastic” for example) this can be a little less focused:

![Listing cmdlets using service name words](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ci61f1vj3q8v9iqd3yae.png)

The `-Service` parameter can also be used with multiple words (`-Service "Compute Cloud"`) and also supports a `-MatchWithRegex` parameter. Note that the `-MatchWithRegex` parameter automatically surrounds the regex you provide with `^` and `$` terms. Also, in the examples I'm showing in this post I’m using mixed case, but case is actually insignificant.

## Finding cmdlets that implement a service API

Having found cmdlets that map to a service, how about the inverse – finding cmdlets that map to AWS service APIs? This is useful for developers used to working with one of the AWS SDKs and who have some familiarity with the underlying services. As an ex-SDK developer, this is my usual go-to approach especially as I’m usually starting from a service’s API reference material.

To map from API to cmdlet, use the`-ApiOperation` parameter to `Get-AWSCmdletName`, and provide the name of the API (case is not significant):

![Looking for a cmdlet by API name](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0pv9yfuoxqp1d3c7vm06.png)

If you want to restrict the search to a particular service, add the `-Service` parameter. Modifying the example above to be `Get-AWSCmdletName -ApiOperation -Service EC2` would output only one result.

You can also perform a regex-based search with `-ApiOperation`:

![Looking for a cmdlet by operation and regex](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/421374bjif4ostxdofvi.png)

## Mapping from an AWS CLI command to a cmdlet

It’s no secret that there are more help examples available for the [AWS CLI](https://aws.amazon.com/cli/) than PowerShell. `Get-AWSCmdletName` has an additional mode, invoked with the `-AwsCliCommand` parameter, that parses a CLI command to output the name of the corresponding cmdlet. This is based on how the CLI command hyphenates the service API name so might not be 100% correct if this convention ever changes. To use it, take the CLI command with the service indicator and operation name and pass it to the cmdlet. You don’t need the initial "aws" component in the CLI command example, and if you pass it, it’s ignored. For example, below I could also have specified `-AwsCliCommand "aws ec2 describe-instances"` to achieve the same result.

![Looking up a cmdlet from CLI command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6u7qgdi3k0axklepl9ck.png)

Note the deprecation warning; personally, I hope this feature isn’t ever removed but, since it’s based on a naming convention rather than internal metadata added when the cmdlets are built, it’s possible it could fall victim to a future change.

The CLI mode doesn’t translate parameters (and ignores them if you include them in the parameter value). Since the CLI and the PowerShell cmdlets map to AWS service APIs, I usually head to the [cmdlet reference](https://docs.aws.amazon.com/powershell/latest/reference/Index.html), or the respective service reference documentation, at that point.

With over 11000 cmdlets available, the tools provide a lot of scope to work with AWS services and resources from PowerShell, but finding out what’s available can be daunting. Hopefully, from this post you can now see how you can find your way around to become productive quickly.

Happy scripting!

## Addendum

[AWS Solutions Architect Vlad Hrybok](https://www.linkedin.com/in/vladhrybok/) informed me of a site that you might also find useful when mapping from AWS CLI commands to the PowerShell cmdlet, [AWS CLI -eq PowerShell](https://aws-cli-eq-pwsh.shibata.tech/). Clicking entries in the Services column takes you to the product details, whereas clicking in the CLI command column takes you to a command/cmdlet list for that service. Super useful!