lib/Merge-MgnSourceMachineTemplateDetails.ps1

function Merge-MgnSourceMachineTemplateDetails {
    <#
    .SYNOPSIS
    Merge a Source Machine's Template with a chosen Base Template and the Parameters provided

    .DESCRIPTION
    This function is provided an MGN Source Server's current Launch Template, Merges changes from the provided Base Template, then merges the Parameters provided by the action

    .PARAMETER MachineLaunchTemplate
    The MGN Source Machine Launch Template

    .PARAMETER BaseLaunchTemplate
    The Base Launch Template used as an override for the Machine's Launch Template

    .PARAMETER Params
    The Params Object provided in an applicable TM Action. The Params object contains values to add to the Machine's Launch Template

    .EXAMPLE
    $MergeSplat = @{
        MachineLaunchTemplate = $MachineLaunchTemplate
        BaseLaunchTemplate = $BaseLaunchTemplate
        Params = $Params
    }
    Merge-MgnSourceMachineTemplateDetails $MergeSplat

    .OUTPUTS
    An updated LaunchTemplate object
    #>


    [CmdletBinding()]
    [OutputType([psobject])]   # Add this if the function has an output
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        $MachineLaunchTemplate,

        [Parameter(Mandatory = $true, Position = 1)]
        $BaseLaunchTemplate,

        [Parameter(Mandatory = $true, Position = 2)]
        $Params
    )

    ## Create a New template data request object
    $NewLaunchTemplateData = [Amazon.EC2.Model.RequestLaunchTemplateData]::new()

    ##
    ## Begin Merging properties from Base and Parameters
    ##
    Write-Host 'Merging Launch Template Details'

    ## Instance Type
    Compare-MachineTemplateDetail -Label 'Instance Type' -CurrentValue $MachineLaunchTemplate.LaunchTemplateData.InstanceType.Value -TMParamValue $Params.InstanceType -TemplateValue $BaseLaunchTemplate.LaunchTemplateData.InstanceType.Value
    $NewLaunchTemplateData.InstanceType = $BaseLaunchTemplate.LaunchTemplateData.InstanceType
    $ValueColor = 'Cyan'

    ## If the Machine Override value in the Parameter is not null, and is not "Use Base Launch Template"
    # if ((-Not [String]::IsNullOrEmpty($Params.($InstanceDetail.Parameter))) -and ($Params.($InstanceDetail.Parameter) -ne 'Use Base Launch Template')) {

    # if ($InstanceDetail.Array) {
    # [Array]$NewLaunchTemplateData.($InstanceDetail.Property) = $Params.($InstanceDetail.Parameter) -split ',' | ForEach-Object { $_.Trim() }

    # }
    # Elseif ($Params.($InstanceDetail.Parameter) -match '^{.*}$') {
    # $NewLaunchTemplateData.($InstanceDetail.Property) = $Params.($InstanceDetail.Parameter) | ConvertFrom-Json
    # }
    # Else {
    # ## Use the string directly
    # $NewLaunchTemplateData.($InstanceDetail.Property) = $Params.($InstanceDetail.Parameter)
    # }

    # $ValueColor = 'Yellow'
    # }

    ## Print the resulting value
    Write-Host "`tResulting Value:`t" -NoNewline
    Write-Host $NewLaunchTemplateData.InstanceType.Value -ForegroundColor $ValueColor

    Write-Host ""
    # @{
    # Label = "Instance Type"
    # Property = "InstanceType"
    # Parameter = "InstanceType"
    # Array = $False
    # }


    ## IAM Role
    ##!! Fails convertsion with error:
    <#
              $NewLaunchTemplateData.($InstanceDetail.Property) = $BaseLaun …
                    | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    | Exception setting "IamInstanceProfile": "Cannot convert the "Amazon.EC2.Model.LaunchTemplateIamInstanceProfileSpecification" value of type "Amazon.EC2.Model.LaunchTemplateIamInstanceProfileSpecification" to type
                    | "Amazon.EC2.Model.LaunchTemplateIamInstanceProfileSpecificationRequest"."
            #>

    # @{
    # Label = "IAM Role"
    # Property = "IamInstanceProfile"
    # Parameter = "IamRole"
    # Array = $False
    # }

    ## Placement Group
    # @{
    # Label = "Placement Group"
    # Property = "Placement"
    # Parameter = "PlacementGroup"
    # Array = $False
    # }

    ## AMI Image
    # @{
    # Label = "AMI Image"
    # Property = "ImageId"
    # Parameter = "IamImage"
    # Array = $False
    # }

    # ## Process Launch Template Instance Details
    # foreach ($InstanceDetail in $LaunchTemplateProperties.Instance) {

    # ## Write the values
    # Write-Host $InstanceDetail.Label

    # Write-Host "`tTM Value:`t`t" -ForegroundColor Yellow -NoNewline
    # Write-Host $Params.($InstanceDetail.Parameter)

    # Write-Host "`tTemplate Value:`t`t" -ForegroundColor Cyan -NoNewline
    # if ($BaseLaunchTemplate.LaunchTemplateData.($InstanceDetail.Property).Arn) { Write-Host $BaseLaunchTemplate.LaunchTemplateData.($InstanceDetail.Property).Arn }
    # elseif ($BaseLaunchTemplate.LaunchTemplateData.($InstanceDetail.Property).Value) { Write-Host $BaseLaunchTemplate.LaunchTemplateData.($InstanceDetail.Property).Value }
    # else { Write-Host $BaseLaunchTemplate.LaunchTemplateData.($InstanceDetail.Property).ToString() }

    # ## Assign the Template Value to the Machine Launch Template
    # $NewLaunchTemplateData.($InstanceDetail.Property) = $BaseLaunchTemplate.LaunchTemplateData.($InstanceDetail.Property)
    # $ValueColor = 'Cyan'

    # ## If the Machine Override value in the Parameter is not null, and is not "Use Base Launch Template"
    # if ((-Not [String]::IsNullOrEmpty($Params.($InstanceDetail.Parameter))) -and ($Params.($InstanceDetail.Parameter) -ne 'Use Base Launch Template')) {

    # if ($InstanceDetail.Array) {
    # [Array]$NewLaunchTemplateData.($InstanceDetail.Property) = $Params.($InstanceDetail.Parameter) -split ',' | ForEach-Object { $_.Trim() }

    # }
    # Elseif ($Params.($InstanceDetail.Parameter) -match '^{.*}$') {
    # $NewLaunchTemplateData.($InstanceDetail.Property) = $Params.($InstanceDetail.Parameter) | ConvertFrom-Json
    # }
    # Else {
    # ## Use the string directly
    # $NewLaunchTemplateData.($InstanceDetail.Property) = $Params.($InstanceDetail.Parameter)
    # }

    # $ValueColor = 'Yellow'
    # }

    # ## Print the resulting value
    # Write-Host "`tResulting Value:`t" -NoNewline
    # if ($NewLaunchTemplateData.($InstanceDetail.Property).Arn) { Write-Host $NewLaunchTemplateData.($InstanceDetail.Property).Arn -ForegroundColor $ValueColor }
    # elseif ($NewLaunchTemplateData.($InstanceDetail.Property).Value) { Write-Host $NewLaunchTemplateData.($InstanceDetail.Property).Value -ForegroundColor $ValueColor }
    # else { Write-Host $NewLaunchTemplateData.($InstanceDetail.Property).ToString() -ForegroundColor $ValueColor }
    # Write-Host ""
    # }


    ##
    ## Network and Security
    ##

    ## Check how many Network Interfaces are present
    Write-Host 'Merging Networking Details'
    if ($MachineLaunchTemplate.LaunchTemplateData.NetworkInterfaces.Count -gt 1) {
        Write-Host "The Target EC2 instance has more than 1 Network Interface. The Settings provided in the Device Record will only apply to the first interface" -ForegroundColor Yellow
    }

    ## These properties is nested in the NetworkInterfaces[]
    # @{
    # Label = "Public IP Action"
    # Property = "publicIPAction"
    # Parameter = "PublicIPAction"
    # Array = $False
    # }

    # @{
    # Label = "Private IP Action"
    # Property = "privateIPAction"
    # Parameter = "PrivateIPAction"
    # Array = $False
    # }
    # @{
    # Label = "Private IP Addresses"
    # Property = "PrivateIpAddresses"
    # Parameter = "PrivateIps"
    # Array = $True
    # }
    # @{
    # Label = "Static IP Action"
    # Property = "staticIpAction"
    # Parameter = "StaticIpAction"
    # Array = $False
    # }
    # @{
    # Label = "Static IP Address"
    # Property = "staticIp"
    # Parameter = "StaticIp"
    # Array = $false
    # }
    # @{
    # Label = "Subnets"
    # Property = "SubnetId"
    # Parameter = "Subnets"
    # Array = $True
    # }
    # @{
    # Label = "Security Groups"
    # Property = "Groups"
    # Parameter = "SecurityGroups"
    # Array = $True
    # }


    # ## Process Launch Template Instance Details
    # foreach ($NetworkingDetail in $LaunchTemplateProperties.Networking) {

    # ## Write the values
    # Write-Host $NetworkingDetail.Label

    # Write-Host "`tTM Value:`t`t" -ForegroundColor Yellow -NoNewline
    # Write-Host $Params.($NetworkingDetail.Parameter)

    # Write-Host "`tTemplate Value:`t`t" -ForegroundColor Cyan -NoNewline
    # Write-Host $BaseLaunchTemplate.LaunchTemplateData.NetworkInterfaces[0].($NetworkingDetail.Property).ToString()

    # ## Assign the Template Value to the Machine Launch Template
    # $NewLaunchTemplateData.NetworkInterfaces[0].($NetworkingDetail.Property) = $BaseLaunchTemplate.LaunchTemplateData.NetworkInterfaces[0].($NetworkingDetail.Property)
    # $ValueColor = 'Cyan'

    # ## If the Machine Override value in the Parameter is not null, and is not "Use Base Launch Template"
    # if ((-Not [String]::IsNullOrEmpty($Params.($NetworkingDetail.Parameter))) -and ($Params.($NetworkingDetail.Parameter) -ne 'Use Base Launch Template')) {

    # if ($NetworkingDetail.Array) {
    # [Array]$NewLaunchTemplateData.NetworkInterfaces[0].($NetworkingDetail.Property) = $Params.($NetworkingDetail.Parameter) -split ',' | ForEach-Object { $_.Trim() }

    # }
    # Elseif ($Params.($NetworkingDetail.Parameter) -match '^{.*}$') {
    # $NewLaunchTemplateData.NetworkInterfaces[0].($NetworkingDetail.Property) = $Params.($NetworkingDetail.Parameter) | ConvertFrom-Json
    # }
    # Else {
    # ## Use the string directly
    # $NewLaunchTemplateData.NetworkInterfaces[0].($NetworkingDetail.Property) = $Params.($NetworkingDetail.Parameter)
    # }

    # $ValueColor = 'Yellow'
    # }

    # ## Print the resulting value
    # Write-Host "`tResulting Value:`t" -NoNewline
    # Write-Host $NewLaunchTemplateData.NetworkInterfaces[0].($NetworkingDetail.Property).ToString() -ForegroundColor $ValueColor
    # Write-Host ""
    # }


    <##
    ### Assembling Tags for the Machine Launch Template
    ###
        1. Add the tags from the BASE Launch template
        2. Add the tags from the PARAMS - JSON format
        3. Add the tags from the PARAMS - Key=Value format
    #>


    ## 1: Update any tags on the machine from the Launch Template Temlate
    # $NewLaunchTemplateData.TagSpecifications = $BaseLaunchTemplate.LaunchTemplateData.TagSpecifications
    # foreach ($TemplateTag in $BaseLaunchTemplate.LaunchTemplateData.TagSpecifications[0].Tags) {

    # ## Remove the existing tag to replace the Template Specific one
    # $ExistingTag = $MachineLaunchTemplate.LaunchTemplateData.TagSpecifications[0].tags | Where-Object { $_.key -eq $TemplateTag.Name }
    # if ($ExistingTag) {
    # $UpdateTags.Remove($ExistingTag)
    # }

    # $MachineLaunchTemplate.LaunchTemplateData.TagSpecifications[0].tags.Add([Amazon.EC2.Model.Tag]::new(
    # $TemplateTag.key,
    # $TemplateTag.Value.Trim()
    # )
    # )
    # }

    # ## 2: Params Handle JSON Object with keys/Arrays
    # if ($Params.Tags -match '^{.*}$') {

    # ## Convert the Parameter provided tags from JSON
    # $ParamTags = $Params.Tags | ConvertFrom-Json -ErrorAction 'SilentlyContinue'

    # ## Add each Parameter-Tag to the Machine Launch Template
    # foreach ($ParamTag in $ParamTags.PSObject.Properties) {

    # ## Remove the existing tag to replace the Machine Specific one
    # $ExistingTag = $MachineLaunchTemplate.LaunchTemplateData.TagSpecifications[0].tags | Where-Object { $_.key -eq $ParamTag.Name }
    # if ($ExistingTag) {
    # $UpdateTags.Remove($ExistingTag)
    # }

    # ## Add the New Tag
    # # [void]$UpdateTags.Add([PSCustomObject]@{
    # # Key = $ParamTag.Name
    # # Value = $ParamTag.Value
    # # })
    # $MachineLaunchTemplate.LaunchTemplateData.TagSpecifications[0].tags.Add([Amazon.EC2.Model.Tag]::new(
    # $ParamTag.Name,
    # $ParamTag.Value[1].Trim()
    # )
    # )
    # }
    # }

    # ## 3: Params - Handle Key=Value, Key2=Value2 values
    # elseif ($Params.Tags -match '.*=.*') {

    # ## Convert the Parameter provided tags from JSON
    # $ParamTags = $Params.Tags -Split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' }
    # foreach ($ParamTag in $ParamTags) {
    # $KVPair = $ParamTag -split '='

    # ## Remove the existing tag to replace the Machine Specific one
    # $ExistingTag = $MachineLaunchTemplate.LaunchTemplateData.TagSpecifications[0].tags | Where-Object { $_.key -eq $KVPair[0] }
    # if ($ExistingTag) {
    # $UpdateTags.Remove($ExistingTag)
    # }

    # ## Add the Replacement Tag
    # $NewLaunchTemplateData.TagSpecifications[0].tags.Add([Amazon.EC2.Model.Tag]::new(
    # $KVPair[0].Trim(),
    # ($KVPair[1] ? $KVPair[1].Trim() : '')
    # )
    # )
    # }
    # }

    ##
    ## Apply Disk Details to all disks
    ##

    if ($MachineLaunchTemplate.LaunchTemplateData.BlockDeviceMappings.Ebs.Count -gt 1) {
        Write-Host "The Target EC2 instance has more than 1 Disk. The Settings provided in the Device Record will apply to ALL of the Disks" -ForegroundColor Yellow
    }

    # ## Apply Disk Type Details to all of the Machine's existing disks
    # if (-Not [String]::IsNullOrEmpty(($Params.DiskType))) {

    # $DiskDetails = $Params.DiskType | ConvertFrom-Json -ErrorAction SilentlyContinue
    # if ($DiskDetails) {
    # $MachineLaunchTemplate.LaunchTemplateData.BlockDeviceMappings.Ebs | ForEach-Object {
    # $_.Iops = $DiskDetails.iops
    # $_.Throughput = $DiskDetails.throughput
    # $_.VolumeType = $DiskDetails.VolumeType
    # }
    # }
    # }

    # ## Use the 'Machine' launch template that was updated with disk info, and replace the property on the UpdatedMachineLaunchTemplate
    # $UpdatedMachineLaunchTemplate.LaunchTemplateData.BlockDeviceMappings = $MachineLaunchTemplate.LaunchTemplateData.BlockDeviceMappings


    ## Return the Machine Launch Temlate
    $UpdatedMachineLaunchTemplate
}