function Get-InstanceMetadata { <# .SYNOPSIS This function wraps the web-request to get the Instance Metadata (IMDS) from an EC2 instance. .DESCRIPTION Defaults to using V2 of the service, which requires a token. This function takes care of the token generation and use. There's also the option to use V1 of the service with the switch $UseImdsV1, which requires no token. .PARAMETER Endpoint The endpoint in the IMDS servicec to fetch. Ex. '/meta-data/hostname' .PARAMETER UseImdsV1 Switch to change to the IMDS V1 request instead of V2. .EXAMPLE $result = Get-InstanceMetadata -Endpoint "/meta-data/hostname" $result = Get-InstanceMetadata -Endpoint "/meta-data/hostname" -UseImdsV1 .NOTES https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html #> [CmdletBinding()] [OutputType([System.String])] Param ( [Parameter(Mandatory = $true)] [string]$Endpoint, [Parameter(Mandatory = $false)] [switch]$UseImdsV1 ) $logLead = (Get-LogLeadName) # Script block to be used when Imds V2 is selected. This is default unless switch $UseImdsV1 is specified. $V2Script = { param ($sbImdsUri, $sbEndpoint, $sbImdsV2Token) $endpoint = ("{0}/{1}" -f $sbImdsUri, $sbEndpoint) try { $metadata = (Invoke-WebRequest -Headers @{"X-aws-ec2-metadata-token" = $sbImdsV2Token} -Method GET -UseBasicParsing -TimeoutSec 5 -Uri $endpoint) } catch [System.Net.WebException] { # Only on 401 $unauthorizedStatusCode = [System.Net.HttpStatusCode]::Unauthorized $response = $_.Exception.Response if($response.StatusCode -eq $unauthorizedStatusCode) { Write-Verbose "401 Unauthorized caught. Trying again with new token." $newToken = Get-ImdsV2Token -InvalidateCache $metadata = (Invoke-WebRequest -Headers @{"X-aws-ec2-metadata-token" = $newToken} -Method GET -UseBasicParsing -TimeoutSec 5 -Uri $endpoint) } } return $metadata } # Script block to be used when ImdsV1 is specified. $V1Script = { param($sbImdsUri, $sbEndpoint) $endpoint = ("{0}/{1}" -f $sbImdsUri, $sbEndpoint) $metadata = (Invoke-WebRequest -Method GET -UseBasicParsing -TimeoutSec 5 -Uri $endpoint) return $metadata } # Set up variables to be passed into the script blocks. $imdsUri = Get-ImdsBaseUri # Switch between the two commands based on the $UseImdsV1 switch param. if($UseImdsV1) { Write-Verbose "$logLead Imds V1 specified, trying command with V1 URI." $result = (Invoke-CommandWithRetry -Arguments ($imdsUri, $Endpoint) -MaxRetries 3 -Exponential -ScriptBlock $V1Script) } else { Write-Verbose "$logLead Imds V2 specified, trying command with V2 URI." $token = Get-ImdsV2Token $result = (Invoke-CommandWithRetry -Arguments ($imdsUri, $Endpoint, $token) -MaxRetries 3 -Exponential -ScriptBlock $V2Script) } return $result }