Create-IpsAwsImage.ps1

<#
 .Synopsis
  Creates an AWS disk image based on the result of the AWS prepare job.

 .Description
  Creates an AWS disk image based on the result of the AWS prepare job.
#>

Function Create-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)]
        [psobject]$Tags = [PSCustomObject]@{},
        [Parameter(Mandatory = $false)]
        [switch]$DryRun = $false,
        [Parameter(Mandatory = $false)]
        [string]$LogFileDir = "",
        [Parameter(Mandatory = $false)]
        [string]$LogFileName = 'CreateToAws.log',
        [Parameter(Mandatory = $false)]
        [switch]$OverwriteLog
    )
    Begin
    {
    }
    Process
    {
        # Initialize Logger
        # Set parameter 'Verbose' by internal parameter 'VerbosePreference', since the option -Verbose is occupied by powershell cmdlet
        if($VerbosePreference -eq 'Continue')
        {
            $Verbose = $True
        } else {
            $Verbose = $False
        }
        LogInit $LogFileName $OverwriteLog $Verbose

        if (($Artifacts.Count -eq 0) -and ($VolumeId -eq $null)) {
            throw "Invalid parameters. Must contain either Artifacts.VolumeId or VolumeId"
        }
        if ($Artifacts.Count -gt 0) {
            # assume artifacts contain VolumeId
            $ArtifactsVolumeId = $Artifacts.VolumeId        
            if (($ArtifactsVolumeId -ne $null) -and ($ArtifactsVolumeId -ne "")) {
                LogIt "Using VolumeId from Artifacts"
                $VolumeId = $ArtifactsVolumeId
            }
        }
        
        if (($ImageName -eq $null) -or ($ImageName -eq "")) {
            LogIt "Using default image name"
            $ImageName = "ImageCreatedFromMigratedVolume-" + $VolumeId
        }
        
        if ($DryRun) {
            LogIt "Using dry run"
            $DryRunString = "--dry-run"
        } else {
            $DryRunString = "--no-dry-run"
        }
        
        $DefaultTagsString = "{Key=SourceScript,Value=CreateIpsAwsImage},{Key=SourceVolume,Value=" + $VolumeId + "}"
        $TagsObject = $Tags | ConvertFrom-Json -AsHashtable
        $TagsString = ($TagsObject.keys.foreach({ "{Key=$_, Value=$($TagsObject[$_])}" }) -join ',')
        
        if (($TagsString -eq $null) -or ($TagsString -eq "")) {
            LogIt "Using default tags"
            $TagsListString = '[' + $DefaultTagsString + ']'
        } else {
            $TagsListString = '[' + $TagsString + ',' + $DefaultTagsString + ']'
        }
        
        try {
            # create the snapshot
            $TagsSpecsString = 'ResourceType=snapshot,Tags=' + $TagsListString
            LogIt "Using TagSpecifications $TagsSpecsString. DryRun $DryRun) VolumeId $VolumeId"
            
            $SnapshotResponse = aws ec2 create-snapshot --description 'Created with a Citrix migrated volume' --volume-id $VolumeId --tag-specifications $TagsSpecsString $DryRunString
            
            if (($LastExitCode -ne 0) -and ($DryRun -eq $false)) {
                throw "Failed to create VM Volume Snapshot. Failed with error code $LastExitCode"
            }

            # demarshall the snapshot id from the response or use a fake id for a dry run
            if ($DryRun) {
                $SnapshotId = "snap-dryrunexample"
            } else {
                $SnapshotResponseObject = $SnapshotResponse | ConvertFrom-Json
                $SnapshotId = $SnapshotResponseObject.SnapshotId
            }

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

            # wait for snapshot to be completed
            aws ec2 wait snapshot-completed --snapshot-ids $SnapshotId $DryRunString
            
            if (($LastExitCode -ne 0) -and ($DryRun -eq $false)) {
                throw "Failed to create snapshot. Failed with error code $LastExitCode"
            }
            
            Write-Host "Snapshot $($SnapshotId) is ready for conversion to 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 $DryRunString

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

            # demarshall the image id from the response
            $ImageResponseObject = $ImageResponse | ConvertFrom-Json
            $ImageId = $ImageResponseObject.ImageId
            LogIt "Created VM Image $ImageName Id $ImageId from snapshot $SnapshotId"
        }
        catch {
            LogIt "Failed to create VM Image $ImageName from volume $VolumeId"
            throw "Failed to create VM: $_"
        }
        return @{
            imageName = $ImageName
            imageId = $ImageId
            snapshotId = $SnapshotId
            dryRun = $DryRun
            tags = $TagsListString
        }
    }
}