Public/Helpers/Find-AzureServiceTag.ps1
|
using namespace System.Management.Automation # used for auto-generating the valid values for the ServiceName parameter class AzureServiceNames : IValidateSetValuesGenerator { [string[]] GetValidValues() { try { # Check if serviceTags is loaded and contains items if ($null -eq $script:SessionVariables -or $null -eq $script:SessionVariables.serviceTags) { Write-Warning "Service tags not loaded. Run Update-ServiceTag first." return @('LoadServiceTagsFirst') } # Extract all unique system services from the service tags array return ($script:SessionVariables.serviceTags | Where-Object { $_.properties.systemService } | ForEach-Object { $_.properties.systemService } | Sort-Object -Unique) } catch { Write-Warning "Error retrieving service names: $_" return @('ErrorLoadingServiceNames') } } } class AzureRegionNames : IValidateSetValuesGenerator { [string[]] GetValidValues() { try { # Check if serviceTags is loaded and contains items if ($null -eq $script:SessionVariables -or $null -eq $script:SessionVariables.serviceTags) { Write-Warning "Service tags not loaded. Run Update-ServiceTag first." return @('LoadServiceTagsFirst') } # Extract all unique regions from the service tags array return ($script:SessionVariables.serviceTags | Where-Object { $_.properties.region } | ForEach-Object { $_.properties.region } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Sort-Object -Unique) } catch { Write-Warning "Error retrieving region names: $_" return @('ErrorLoadingRegionNames') } } } function Find-AzureServiceTag { <# .SYNOPSIS Searches Azure Service Tags to find IP ranges and service information. .DESCRIPTION Searches Azure Service Tags to identify services for IP addresses or filtering. .PARAMETER IPAddress The IP address to lookup in Azure service tags (IPv4 or IPv6). .PARAMETER ServiceName The Azure service name to filter by. .PARAMETER Region The Azure region to filter by. .PARAMETER AsJson Returns results in JSON format. .PARAMETER Detailed Returns detailed results with all properties. .EXAMPLE Find-AzureServiceTag -IPAddress "20.38.98.100" Searches for which Azure service tag contains the specified IP address. .EXAMPLE Find-AzureServiceTag -ServiceName "AzureStorage" -Region "westeurope" Returns all service tags for Azure Storage in West Europe. .NOTES Requires running Update-AzureServiceTag first to load the service tag data. .LINK MITRE ATT&CK Tactic: TA0043 - Reconnaissance https://attack.mitre.org/tactics/TA0043/ .LINK MITRE ATT&CK Technique: T1590.005 - Gather Victim Network Information: IP Addresses https://attack.mitre.org/techniques/T1590/005/ #> [CmdletBinding(DefaultParameterSetName = 'ByFilters')] [Alias('Get-ServiceTag', 'Find-ServiceTag', 'azure-service-tag', 'find-service-tag')] [OutputType([PSCustomObject[]])] param ( [Parameter( Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByIP', HelpMessage = "IP address to lookup in Azure service tags (IPv4 or IPv6)" )] [Alias('ip', 'address', 'host')] [ValidateScript({ if ($_ -match '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::1$|^\*\.') { return $true } throw "Invalid IP address format. Please provide a valid IPv4 or IPv6 address." })] [string[]]$IPAddress, [Parameter( Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByFilters', HelpMessage = "Azure service name to filter by" )] [ValidateSet([AzureServiceNames])] [Alias('service', 'svc', 'service-name')] [string]$ServiceName, [Parameter( Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByFilters', HelpMessage = "Azure region to filter by" )] [ValidateSet([AzureRegionNames])] [Alias('location', 'region-name', 'loc')] [string]$Region, [Parameter(Mandatory = $false)] [Alias('json', 'raw')] [switch]$AsJson, [Parameter(Mandatory = $false)] [Alias('table', 'list')] [switch]$Detailed ) begin { # Check if service tags are loaded if ($null -eq $script:SessionVariables -or $null -eq $script:SessionVariables.serviceTags -or ($script:SessionVariables.serviceTags).count -le 1) { $errorMsg = "Service tags not loaded. Please run the 'Update-ServiceTag' function." Write-Error $errorMsg -ErrorAction Stop } $results = @() # Create filter for the CIDR to improve performance if IP address is provided if ($IPAddress) { foreach ($ip in $IPAddress) { if ($ip -match '^([0-9A-Fa-f]{1,4}):([0-9A-Fa-f]{1,4}):') { Write-Verbose "Processing IPv6 address: $ip" $firstTwoSegments = $ip.Split(':')[0..1] -join ':' } else { Write-Verbose "Processing IPv4 address: $ip" $firstTwoSegments = $ip.Split('.')[0..1] -join '.' } } } } process { try { if ($IpAddress) { $results = @() $SessionVariables.serviceTags | ForEach-Object { # Check if the IP address matches any of the service tag prefixes within the CIDR range Write-Verbose "Checking service tag: $($_.Name)" foreach ($prefix in $_.properties.addressPrefixes) { if ($IpAddress.Contains("*")) { if ($prefix -match "^$firstTwoSegments") { $addresses = @(Get-CidrAddresses -CidrRange $prefix) if ($addresses -match "$($ipAddress)") { $result = [PSCustomObject]@{ ServiceTagName = $_.Name changeNumber = $_.properties.changeNumber region = ($_.Name.split('.'))[1] regionId = $_.properties.regionId platform = $_.properties.platform systemService = $_.properties.systemService addressPrefixes = $prefix networkFeatures = $_.properties.networkFeatures } $results += $result } } } elseif ($prefix -match "^$firstTwoSegments") { $ip = [System.Net.IPAddress]::Parse($IpAddress) $network = [System.Net.IPNetwork]::Parse($prefix) if ($network.Contains($ip)) { $result = [PSCustomObject]@{ ServiceTagName = $_.Name changeNumber = $_.properties.changeNumber region = ($_.Name.split('.'))[1] regionId = $_.properties.regionId platform = $_.properties.platform systemService = $_.properties.systemService addressPrefixes = $prefix networkFeatures = $_.properties.networkFeatures } $results += $result } } } } if ($results.Count -eq 0) { $results = "No matching service tag found for the given IP address." } } else { $filteredTags = $SessionVariables.serviceTags | Where-Object { $_.properties.region -like "*$Region*" -and $_.properties.systemService -like "*$ServiceName*" } # Create detailed results if needed $results = @() foreach ($tag in $filteredTags) { foreach ($prefix in $tag.properties.addressPrefixes) { if ($Detailed) { $results += [PSCustomObject]@{ ServiceTagName = $tag.Name SystemService = $tag.properties.systemService Region = $tag.properties.region RegionId = $tag.properties.regionId Platform = $tag.properties.platform ChangeNumber = $tag.properties.changeNumber AddressPrefix = $prefix NetworkFeatures = $tag.properties.networkFeatures -join ',' } } else { $results += [PSCustomObject]@{ SystemService = $tag.properties.systemService Region = $tag.properties.region AddressPrefix = $prefix } } } } } # Format the output based on switches if ($AsJson) { return ($results | ConvertTo-Json -Depth 4) } elseif ($Detailed) { return ($results | Format-Table -AutoSize) } else { return $results } } catch { Write-Message -FunctionName $($MyInvocation.MyCommand.Name) -Message $($_.Exception.Message) -Severity 'Error' } } } |