Instantly share code, notes, and snippets.
Last active
April 30, 2025 16:07
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save panasenco/47a4f097bbfe263ad09a35f5defbbc64 to your computer and use it in GitHub Desktop.
Bulk tagging AWS resources from a spreadsheet - see blog post: https://dev.to/panasenco/tag-aws-from-spreadsheet-3ild. Install from https://www.powershellgallery.com/packages/Export-AwsTags with `Install-Module Export-AwsTags -Scope CurrentUser`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Module manifest for module 'Export-AwsTags' | |
# | |
@{ | |
ModuleVersion = '1.1' | |
GUID = '56367acd-8b8b-4c62-bc9e-f43aab12ac3c' | |
Author = 'Aram Panasenco' | |
Copyright = '(c) 2025 Aram Panasenco. All rights reserved.' | |
Description = 'Bulk export tags from a CSV file into AWS' | |
PowerShellVersion = '5.1' | |
NestedModules = 'Export-AwsTags.psm1' | |
FunctionsToExport = @('Export-AwsTags', 'Import-AutoScalingGroupTags', 'Update-CsvColumnOrder') | |
CmdletsToExport = @() | |
VariablesToExport = @() | |
AliasesToExport = @() | |
FileList = @('Export-AwsTags.psd1','Export-AwsTags.psm1') | |
PrivateData = @{ | |
PSData = @{ | |
Tags = @('AWS') | |
LicenseUri = 'https://mit-license.org/' | |
ProjectUri = 'https://gist.github.com/panasenco/47a4f097bbfe263ad09a35f5defbbc64' | |
} | |
} | |
HelpInfoURI = 'https://dev.to/panasenco/tag-aws-from-spreadsheet-3ild' | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.Synopsis | |
Bulk export tags from a CSV file into AWS | |
.Description | |
AWS Tag Editor allows a bulk download of tag values to a CSV file, but doesn't allow a CSV file with modifications to be uploaded back. | |
This PowerShell function bridges that gap. | |
Simply download the CSV file from the bulk editor, change the tags, then pass the path to this function along with the list of tags you changed. | |
Note that this function can not remove tags, only add or change their values. | |
.Parameter CsvPath | |
Path to the CSV spreadsheet containing the column ARN along with "Tag: <Tag name>" columns. | |
NOTE that values of '(not tagged)' are not sent to AWS at all, so changing a tag value to '(not tagged)' will not actually remove that tag. | |
Also note that values of '-' are converted to empty strings. | |
.Parameter ExportTags | |
List of tags to export to AWS from the spreadsheet. | |
All other columns are ignored. | |
.Parameter AwsProfile | |
Name of the AWS profile to use. | |
.Example | |
Export-AwsTags -CsvPath ~\Downloads\resources.csv -ExportTags @('My important tag 1', 'My important tag 2') -AwsProfile dev | |
#> | |
function Export-AwsTags { | |
param ( | |
[Parameter(Mandatory=$true)][string] $CsvPath, | |
[Parameter(Mandatory=$true)][string[]] $ExportTags, | |
[Parameter()][string] $AwsProfile = 'default' | |
) | |
Import-Csv -Path $CsvPath | foreach { | |
$Row = $_ | |
$Payload = [pscustomobject]@{ | |
ResourceARNList = @($Row.ARN) | |
Tags = [pscustomobject]@{} | |
} | |
$ExportTags | foreach { | |
$Value = $Row."Tag: $_" | |
if ($Value -ne '(not tagged)') { | |
if ($Value -eq '-') { | |
$Value = '' | |
} | |
Add-Member -InputObject $Payload.Tags -MemberType NoteProperty -Name $_ -Value $Value | |
} | |
} | |
$PayloadFile = New-TemporaryFile | |
New-Item -Force -Path $PayloadFile -Value ($Payload | ConvertTo-Json -Compress) | Out-Null | |
Write-Host "Tagging AWS resource $($Row.ARN)" | |
aws resourcegroupstaggingapi tag-resources --profile $AwsProfile --cli-input-json "file://$PayloadFile" | |
} | |
} | |
<# | |
.Synopsis | |
Import tags for autoscaling groups in a format that's compatible with the output of AWS Tag Editor. | |
.Description | |
The AWS Tag Editor and the Resource Groups Tagging API don't currently support fetching tags for EC2 autoscaling groups. | |
This PowerShell function bridges that gap. | |
.Parameter CsvPath | |
Path to the CSV spreadsheet to export to. | |
.Parameter AwsProfile | |
Name of the AWS profile to use | |
.Example | |
Import-AutoScalingGroupTags -CsvPath ~\Downloads\dev-asg-tags.csv -AwsProfile dev | |
#> | |
function Import-AutoScalingGroupTags { | |
param ( | |
[Parameter(Mandatory=$true)][string] $CsvPath, | |
[Parameter()][string] $AwsProfile = 'default' | |
) | |
$AutoScalingGroups = (aws autoscaling describe-auto-scaling-groups --profile $AwsProfile | ConvertFrom-Json).AutoScalingGroups | |
$Columns = $AutoScalingGroups.Tags.Key | sort | Get-Unique | |
$AutoScalingGroups | foreach { | |
$Row = [pscustomobject]@{ARN = $_.AutoScalingGroupARN} | |
$Tags = $_.Tags | |
$Columns | foreach { | |
$Column = $_ | |
$MatchingTags = $Tags | where { $_.Key -eq $Column } | |
if (($MatchingTags | Measure-Object).Count -gt 0) { | |
$Value = $MatchingTags[0].Value | |
} else { | |
$Value = '(not tagged)' | |
} | |
$Row | Add-Member -MemberType NoteProperty -Name "Tag: $Column" -Value $Value | |
} | |
$Row | |
} | Export-Csv -Path $CsvPath -NoTypeInformation | |
} | |
<# | |
.Synopsis | |
Reorder columns in a CSV file to make certain columns appear first. | |
.Description | |
Given a list of "first columns", makes those columns appear first in a given CSV file in that exact order. | |
All other columns will appear after in their original order. | |
Helpful in manually editing massive autogenerated CSV files. | |
.Parameter CsvPath | |
Path to the CSV spreadsheet to be reordered. | |
.Parameter FirstColumns | |
List of columns that must appear first in the CSV file. | |
If a column doesn't exist, it will be inserted with blank values. | |
.Parameter DefaultValue | |
Default value to use when a column from FirstColumns doesn't exist. | |
.Example | |
Update-CsvColumnOrder -CsvPath ~\Downloads\resources.csv -FirstColumns @('ARN', 'Tag: My important tag 1', 'Tag: My important tag 2') -DefaultValue '(not tagged)' | |
#> | |
function Update-CsvColumnOrder { | |
param ( | |
[Parameter(Mandatory=$true)][string] $CsvPath, | |
[Parameter(Mandatory=$true)][string[]] $FirstColumns, | |
[Parameter()][string] $DefaultValue = '' | |
) | |
$SortedRows = Import-Csv -Path $CsvPath | foreach { | |
$Row = $_ | |
$Columns = $Row | Get-Member -Type NoteProperty | |
$RemainingColumns = for ($i = 0; $i -lt $FirstColumns.count; $i++) { | |
[pscustomobject]@{ | |
Name = $FirstColumns[$i] | |
SortIndex = $i | |
New = $true | |
} | |
} | |
for ($i = 0; $i -lt $Columns.count; $i++) { | |
$FirstColumnIndex = $FirstColumns.IndexOf($Columns[$i].Name) | |
if ($FirstColumnIndex -ge 0) { | |
$SortIndex = $FirstColumnIndex | |
$RemainingColumns = $RemainingColumns | where { $_.Name -ne $Columns[$i].Name} | |
} else { | |
$SortIndex = $FirstColumns.count + $i | |
} | |
$Columns[$i] | Add-Member -MemberType NoteProperty -Name SortIndex -Value $SortIndex | |
} | |
$SortedRow = [pscustomobject]@{} | |
($Columns + $RemainingColumns) | sort { $_.SortIndex } | foreach { | |
if ($_.New) { | |
$Value = $DefaultValue | |
} else { | |
$Value = $Row.($_.Name) | |
} | |
Add-Member -InputObject $SortedRow -Type NoteProperty -Name $_.Name -Value $Value | |
} | |
$SortedRow | |
} | |
if (($SortedRows | Measure-Object).Count -gt 0) { | |
$SortedRows | Export-Csv -Path $CsvPath -NoTypeInformation | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment