Skip to content

Instantly share code, notes, and snippets.

@RylandDeGregory
Created June 6, 2021 18:01
Show Gist options
  • Save RylandDeGregory/7d71d74be3a6dbc3c705099be383bbe0 to your computer and use it in GitHub Desktop.
Save RylandDeGregory/7d71d74be3a6dbc3c705099be383bbe0 to your computer and use it in GitHub Desktop.
Generate a CSV report of all Azure and AWS disks (volumes) that are not attached to a virtual machine
#Requires -Version 6.0
#Requires -Modules Az.Accounts, Az.ResourceGraph, AWS.Tools.Common, AWS.Tools.SecurityToken, AWS.Tools.EC2
<#
.SYNOPSIS
Generate a report of cloud (Azure & AWS) orphaned volumes
.DESCRIPTION
Generate a report of Azure Disks and AWS EBS Volumes which are not attached to any virtual machine
.EXAMPLE
Process all Azure Subscriptions, multiple AWS Accounts, and multiple AWS Regions
.\Get-CloudOrphanedVolumes.ps1 -AccessKey 'AKWAVDLECACDWDL' -SecretKey 'Acs320xcew2ds2SLdwsf0' -AWSAccount '12345679012', '123049238343' -AWSRegion 'us-east-1', 'us-west-2'
.EXAMPLE
Process all Azure Subscriptions, a single AWS Account, and all AWS Regions
.\Get-CloudOrphanedVolumes.ps1 -AccessKey 'AKWAVDLECACDWDL' -SecretKey 'Acs320xcew2ds2SLdwsf0' -AWSAccount '12345679012'
.OUTPUTS
Report in CSV format containing information on all cloud orphaned volumes is exported to the current user profile directory.
#>
#region Init
param(
[Parameter(Mandatory)]
[string] $AccessKey,
[Parameter(Mandatory)]
[string] $SecretKey,
[Parameter(Mandatory)]
[string[]] $AWSAccount,
[Parameter(Mandatory)]
[string[]] $AWSRegion
)
# Report location
if ($IsWindows) {
$ReportFile = "$env:USERPROFILE\CloudOrphanedVolumes_$(Get-Date -Format 'yyyy-MM-dd').csv"
} else {
$ReportFile = "$env:HOME/CloudOrphanedVolumes_$(Get-Date -Format 'yyyy-MM-dd').csv"
}
# AWS variables
if (-not $AWSRegion) {
$AWSRegion = Get-AWSRegion
}
$RoleRegion = 'us-east-1'
$RoleName = 'MyEC2Role'
#endregion Init
#region ProcessAzure
try {
# Login to Azure and select correct Subscriptions
Connect-AzAccount
$Subscriptions = Get-AzSubscription | Select-Object -ExpandProperty Id
} catch {
Write-Error "Error connecting to Azure: $_" -ErrorAction Stop
}
try {
$Query = @'
resources
| where type =~ 'microsoft.compute/disks'
| where (coalesce(split(managedBy, '/')[(-1)], '-')) =~ '-'
'@
# Execute Azure Resource Graph query to find orphaned disks in all Subscriptions
$AzOrphanedVols = Search-AzGraph -Subscription $Subscriptions -Query $Query -First 1000 | Select-Object -ExpandProperty Data
} catch {
Write-Error "Error executing Azure Resource Graph query: $_"
}
$AzOrphanedVolObjects = foreach ($OrphanedVol in $AzOrphanedVols) {
# Construct Azure output objects
[PSCustomObject]@{
Cloud = 'Azure'
Account = $OrphanedVol.subscriptionId
Region = $OrphanedVol.location
Id = $OrphanedVol.id
Name = $OrphanedVol.name
SizeGB = $OrphanedVol.properties.diskSizeGB
CreationDate = $OrphanedVol.properties.timeCreated
}
}
#endregion ProcessAzure
#region ProcessAWS
$AWSOrphanedVolObjects = foreach ($Account in $AWSAccount) {
try {
# Assume Role in each Account and set AWS credential
$EC2RoleParams = @{
RoleArn = "arn:aws:iam::$($Account):role/$RoleName"
RoleSessionName = 'EC2OrphanedVolsReport'
AccessKey = $AccessKey
SecretKey = $SecretKey
Region = $RoleRegion
}
$EC2Credential = Use-STSRole @EC2RoleParams | Select-Object -ExpandProperty Credentials
Write-Verbose "Successfully accessed AWS Account [$Account]"
} catch [System.InvalidOperationException] {
if ($AWSAccount.Count -gt 1) {
Write-Warning "No access to AWS Account [$Account]"
continue
} else {
Write-Error "No access to AWS Account [$Account]" -ErrorAction Stop
}
} catch {
Write-Error "Error assuming role in AWS Account [$Account]: $_"
}
# Search all AWS Regions provided
foreach ($Region in $AWSRegion) {
try {
# Get all EBS Volumes in the current region that are not attached to an EC2 Instance
Write-Verbose "Now processing AWS region [$Region]"
$AWSVolumes = Get-EC2Volume -Credential $EC2Credential -Region $Region -Filter @{ Name = 'status'; Values = 'available' }
} catch {
Write-Error "Error getting EBS Volumes from AWS Account [$Account] in region [$Region]: $_"
}
foreach ($Volume in $AWSVolumes) {
# Construct AWS output objects
[PSCustomObject]@{
Cloud = 'AWS'
Account = $Account
Region = $Region
Id = $Volume.VolumeId
Name = $Volume.Tags | Where-Object { $_.key -eq 'Name' } | Select-Object -ExpandProperty value
SizeGB = $Volume.Size
CreationDate = $Volume.CreateTime
}
}
}
}
#endregion ProcessAWS
#region Output
try {
# Export PowerShell object arrays to CSV file
$AzOrphanedVolObjects | Export-Csv -Path $ReportFile -NoTypeInformation
$AWSOrphanedVolObjects | Export-Csv -Path $ReportFile -NoTypeInformation -Append
} catch {
Write-Error "Error exporting orphaned volumes object array to CSV file [$ReportFile]: $_"
}
#endregion Output
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment