New-IpsAwsImage.ps1

<#
.SYNOPSIS
Create an Amazon Machine Image from the result of an Image Portability Service AWS image prepare job.

.DESCRIPTION
Creates an Amazon Machine Image (AMI) from the volume containing the prepared image resulting from an Image Portability Service AWS image prepare job.
An intermediate EC2 snapshot is also created. The id of the volume to turn into the AMI is specified either by piping the output of Wait-IpsJob into this command or explicitly using the -VolumeId parameter. The volume id of the prepared image for an already completed job can be found in the output from running the Get-IpsJob command.

.PARAMETER ImageName
Specifies the name for the created image. If unspecified a name is chosen by the system and will be shown in the output.

.PARAMETER Tags
Specifies a hash table of string values to apply as labels to the created disk image.

.PARAMETER LogFileDir
Specifies the path to the file to log to. The local directory is the default.

.PARAMETER LogFileName
Specifies the name of the file to log to.

.PARAMETER OverwriteLog
If specified the log file is overwritten otherwise it is appended to.

.INPUTS
PSCustomObject. The output from Wait-IpsJob after waiting on an AWS prepare job.

.OUTPUTS
PSCustomObject. A custom object including the image name, image id, and the intermediate snapshot id.

.EXAMPLE
PS> Start-IpsAwsPrepareJob ... | Wait-IpsJob | New-IpsAwsImage -ImageName example-image

.EXAMPLE
PS> $job = Get-IpsJob aef7aa4a-19e7-46fd-b3c7-1f87ddfa375e
PS> New-IpsAwsImage -ImageName example-image -VolumeId $job.additionalInfo.artifacts.output.id
#>


Function New-IpsAwsImage
{
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] # Artifacts come from pipeline and contain the volume id
        [psobject]$Artifacts = [PSCustomObject]@{},
        [Parameter(Mandatory = $false)]
        [string]$VolumeId,  # use VolumeId if no Artifacts
        [Parameter(Mandatory = $false)]
        [string]$ImageName,
        [Parameter(Mandatory = $false)]
        [HashTable]$Tags = @{},
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [string]$LogFileDir,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [string]$LogFileName = 'CreateToAws.log',
        [Parameter(Mandatory = $false)]
        [switch]$OverwriteLog
    )
    Begin
    {
    }
    Process
    {
        try {
            # Set parameter 'Verbose' by internal parameter 'VerbosePreference', since the option -Verbose is occupied by powershell cmdlet
            $Verbose = $VerbosePreference -eq 'Continue'
            LogInit $MyInvocation $LogFileDir $LogFileName $OverwriteLog $Verbose

            VersionCheck $Deployment $CustomerId

            if (($Artifacts.Count -eq 0) -and [String]::IsNullOrWhiteSpace($VolumeId)) {
                throw "Invalid parameters. Must contain either Artifacts or VolumeId"
            }

            if ([String]::IsNullOrWhiteSpace($VolumeId)) {
                # Get volume ID from the artifacts
                try {
                    if ($Artifacts | Get-Member "volumeId") {
                        $VolumeId = $Artifacts.volumeId
                    } else {
                        $VolumeId = $Artifacts["output"][0].id
                    }
                } catch {
                }
                if ([String]::IsNullOrWhiteSpace($VolumeId)) {
                    LogIt 'Invalid Artifacts' $False
                    LogIt ($Artifacts | Out-String) $False
                    throw "Invalid Artifacts"
                }
                LogIt "Using volume $volumeId from Artifacts"
            }

            if ([String]::IsNullOrWhiteSpace($ImageName)) {
                $ImageName = "ImageCreatedFromMigratedVolume-" + $VolumeId
                LogIt "Using default image name $ImageName"
            }

            $DefaultTagsString = "{Key=SourceScript,Value=New-IpsAwsImage},{Key=SourceVolume,Value=" + $VolumeId + "}"
            $TagsString = $Tags.keys.foreach({ "{Key=$_, Value=$($Tags[$_])}" }) -join ','

            if ([String]::IsNullOrWhiteSpace($TagsString)) {
                LogIt "Using default tags"
                $TagsListString = '[' + $DefaultTagsString + ']'
            } else {
                $TagsListString = '[' + $TagsString + ',' + $DefaultTagsString + ']'
            }

            try {
                # create the snapshot
                $TagsSpecsString = 'ResourceType=snapshot,Tags=' + $TagsListString
                LogIt "Creating snapshot from volume $VolumeId with TagSpecifications $TagsSpecsString"

                $SnapshotResponse = aws ec2 create-snapshot --description 'Created with a Citrix migrated volume' --volume-id $VolumeId --tag-specifications $TagsSpecsString

                if ($LastExitCode -ne 0) {
                    throw "Failed to create VM Volume Snapshot. Failed with error code $LastExitCode"
                }

                $SnapshotResponseObject = $SnapshotResponse | ConvertFrom-Json
                $SnapshotId = $SnapshotResponseObject.SnapshotId

                LogIt "Initiated snapshot creation $snapshotId from volume $VolumeId. Waiting for snapshot to be completed ..."

                # wait for snapshot to be completed
                aws ec2 wait snapshot-completed --snapshot-ids $SnapshotId

                if ($LastExitCode -ne 0) {
                    throw "Failed to create snapshot. Failed with error code $LastExitCode"
                }

                Write-Host "Snapshot $($SnapshotId) is ready for conversion to an image"

                # create the image
                $BlockDeviceMappingsString = 'DeviceName=/dev/sda1,Ebs={SnapshotId=' + $SnapshotId + '}'

                $ImageResponse = aws ec2 register-image --name $ImageName --architecture 'x86_64' --root-device-name '/dev/sda1' --boot-mode uefi --ena-support --virtualization-type 'hvm' --block-device-mappings $BlockDeviceMappingsString

                if ($LastExitCode -ne 0) {
                    throw "Failed to create VM Image. Failed with error code $LastExitCode"
                }

                $ImageResponseObject = $ImageResponse | ConvertFrom-Json
                $ImageId = $ImageResponseObject.ImageId
                LogIt "Created VM Image $ImageName ($ImageId) from snapshot $SnapshotId"

                $output = [PSCustomObject]@{
                    ImageName = $ImageName
                    ImageId = $ImageId
                    SnapshotId = $SnapshotId
                    Tags = $TagsListString
                }

                Write-Output $output
            }
            catch {
                LogFatal "Failed to create VM Image $ImageName from volume $($VolumeId): $_"
            }
        }
        finally {
            # Clear credentials if at end of a pipeline
            if (($PSCmdlet.MyInvocation.PipelinePosition -eq $PSCmdlet.MyInvocation.PipelineLength) -and ($PSCmdlet.MyInvocation.PipelineLength -gt 1)) {
                Clear-XDCredentials
            }
        }
    }
}