Copying AWS EC2 Tags to EBS Using PowerShell

These days when creating an EC2 instance in the AWS console UI, by default, the tags are duplicated across Elastic Block Service (EBS) and Elastic Network Interface (ENI) attached resources being created. But what happens if you have an older instance that didn’t do that or you add tags to an EC2 instance and need it to reflect across attached resources? It’s easy when you only have a few EC2 instances. Just copy/paste in the console UI. But what if you have them in bulk?

I did my Googling and came across what seemed to be the quickest solution: AWS PowerShell (yes, I’m a Windows user)

I came across “Tag AWS EC2 EBS volumes with the instance name tag” by Alex Neihaus written in 2017 and modified it slightly to fit my needs. But as a new user to AWS PowerShell, it took me a little bit of a learning curve, especially as the method has changed from a legacy Windows-specific, single, large-module version of AWS Tools for PowerShell. Instead, I used a modularized version of AWS Tools for PowerShell where each AWS service is supported by its own individual, small module, with shared support modules AWS.Tools.Common and AWS.Tools.Installer.

Check out “Installing the AWS Tools for PowerShell on Windows” for great information on how to get started.

First of all, install the AWS.Tools.Installer module:

Install-Module -Name AWS.Tools.Installer

Then install the EC2 module

Install-AWSToolsModule AWS.Tools.EC2 -CleanUp

Next, create an access key in IAM via the IAM Console UI. If you have a policy attached that denies services access until you are using MFA (MultiFactorAuthPresent), you will need to use an IAM account without that condition or learn how to create temporary sessions with MFA. If you have this check enabled, you will come across a “…is not authorized to perform…with an explicit deny in an identity-based policy” error. Next, add your key information to the SDK Key Store. See “Using AWS Credentials” for information.

Set-AWSCredential `
-AccessKey {myaccesskey} `
-SecretKey {mysecretkey} `
-StoreAs {myCredentialProfileNameIJustMadeUp}

You can see a list of stored credentials using:

Get-AWSCredential -ListProfileDetail

Next, I ran the following script modified from https://www.yobyot.com/aws/tag-aws-ec2-ebs-volumes-with-the-instance-name-tag/2017/02/05/. If you want to copy more than one key name from each EC2 instance, you can run this script multiple times, just replacing the three “Name” tag labels in the code below with another tag key name, such as “Owner” for example. After iterating through this I did find a way to automatically iterate through all tags using this GitHub Gist: https://gist.github.com/dezren39/83e8453be4777c260dee5a2c56127249, but I haven’t tested it.

Set-AWSCredentials -ProfileName {myCredentialProfileNameIJustMadeUp}
Set-DefaultAWSRegion -Region us-east-1

(Get-EC2Instance).Instances | `
ForEach-Object -Process {
    # Get the name tag of the current instance ID; Amazon.EC2.Model.Tag is in the Instances object
    $instanceName = $_.Tags | Where-Object -Property Key -EQ "Name" | Select-Object -ExpandProperty Value
    $_.BlockDeviceMappings | ` # Pass all the current block device objects down the pipeline
    ForEach-Object -Process {
        $volumeid = $_.ebs.volumeid # Retrieve current volume id for this BDM in the current instance
        # Get the current volume's Name tag
        $volumeNameTag = Get-EC2Tag -Filter @(@{ name = 'tag:Name'; values = "*" }; @{ name = "resource-type"; values = "volume" }; @{ name = "resource-id"; values = $volumeid }) | Select-Object -ExpandProperty Value
        
        if (-not $volumeNameTag) # Replace the tag in the volume if it is blank
        {
            New-EC2Tag -Resources $volumeid -Tags @{ Key = "Name"; Value = $instanceName } # Add volume name tag that matches InstanceID
        }
    }
}

Next, I need to figure out how to copy tags from EC2 into ENI (Elastic Network Interfaces).