Created
June 6, 2021 18:01
-
-
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
This file contains 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
#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