Private/Set-VMPreparation.ps1

function Global:Set-VMPreparation {
    [CmdletBinding()]
    <#
    .SYNOPSIS
        ...
    .DESCRIPTION
        ...
    #>

    param(        
        [Parameter(Mandatory = $true)]
        [string]
        $ResourceGroupName,        
        [Parameter(Mandatory = $true)]
        [string]
        $ResourceLocation,
        [Parameter(Mandatory = $true)]
        [string]
        [Alias("Version")]
        [string]
        $BCVersion,
        [Alias("CumulativeUpdate")]
        [Parameter(Mandatory = $false)]
        [string]
        $BCCumulativeUpdate,
        [Alias("Language")]
        [Parameter(Mandatory = $false)]
        [string]
        $BCLanguage,
        [ValidateSet('App', 'Web')]
        [string]
        $InstallationType = "App",
        [Parameter(Mandatory = $false)]
        [string]
        $DownloadDirectory,
        [Parameter(Mandatory = $false)]
        [string]
        $ConfigurationFile,
        [Parameter(Mandatory = $false)]
        [string]
        $LicenseFilename,
        [Parameter(Mandatory = $true)]
        [string]
        $VMName,
        [Parameter(Mandatory = $true)]
        [string]
        $LocalPropScaleSetName,
        [Parameter(Mandatory = $true)]
        [string]
        $LocalPropStorageAccountName
    )
    process {
        $VirtualMachine = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VMName -ErrorAction SilentlyContinue
        if (-not($VirtualMachine)) {
            throw "VM $VMName does not exist"
        }
        
        # Prepare parameter
        $bcVersionArgs = @{ }
        foreach ($param in $PsBoundParameters.GetEnumerator() | Where-Object { $_.Key -like "BC*" }) {
            $bcVersionArgs.Add($param.Key.Remove(0, 2), $param.Value)
        }
        $localProperties = @{
            ScaleSetName       = $LocalPropScaleSetName
            ResourceGroupName  = $ResourceGroupName
            StorageAccountName = $LocalPropStorageAccountName
        }        
        $scriptExecutionParams = @{
            ResourceGroupName = $ResourceGroupName
            ResourceLocation  = $ResourceLocation
            VMName            = $VMName
        }
        $installBCParams = @{
            InstallationType = $InstallationType
        }
        if (-not([string]::IsNullOrEmpty($DownloadDirectory))) {
            $installBCParams.Add('DownloadDirectory', $DownloadDirectory)
        }
        if (-not([string]::IsNullOrEmpty($ConfigurationFile))) {
            $installBCParams.Add('ConfigurationFile', $ConfigurationFile)
        }
        if (-not([string]::IsNullOrEmpty($LicenseFilename))) {
            $installBCParams.Add('LicenseFilename', $LicenseFilename)
        }
        if (-not([string]::IsNullOrEmpty($BCVersion))){
            $installBCParams.Add('Version', $BCVersion)
        }
        Submit-ScriptToVmAndExecute @scriptExecutionParams -ScriptBlockName InstallD365Module -MsgBeforeExecuting "Attempting to Install module on VM..."
        Submit-ScriptToVmAndExecute @scriptExecutionParams -ScriptBlockName InitVM -MsgBeforeExecuting "Attempting to initialize some basics on VM..."
        Submit-ScriptToVmAndExecute @scriptExecutionParams -ScriptBlockName DownloadBC -RunParameter $bcVersionArgs -MsgBeforeExecuting "Attempting to download BC to VM..."
        Submit-ScriptToVmAndExecute @scriptExecutionParams -ScriptBlockName InstallBC -RunParameter $installBCParams -MsgBeforeExecuting "Attempting to install BC to VM..."

        Submit-ScriptToVmAndExecute @scriptExecutionParams -ScriptBlockName WriteProperties $localProperties -MsgBeforeExecuting "Attempting to set local properties for autostart-update..."
        Submit-ScriptToVmAndExecute @scriptExecutionParams -ScriptBlockName CreateUpdateScheduledTask -MsgBeforeExecuting "Attempting to create scheduled task for auto-updating..."
        
        Submit-ScriptToVmAndExecute @scriptExecutionParams -ScriptBlockName GeneralizeVM -MsgBeforeExecuting "Attempting to generalize VM (calling sysprep.exe)..."
        
        $vmStatus = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VMName -Status).Statuses[1].Code
        $vmStatusReadyToProceed = ($vmStatus -eq 'PowerState/stopped') -or ($vmStatus -eq 'PowerState/deallocated')
        if (-not($vmStatusReadyToProceed)) {
            Write-CustomHost -Message "Wating for VM to finalize sysprep..."
            while (-not $vmStatusReadyToProceed) {
                Start-Sleep -Seconds 2
                $vmStatus = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VMName -Status).Statuses[1].Code
                $vmStatusReadyToProceed = ($vmStatus -eq 'PowerState/stopped') -or ($vmStatus -eq 'PowerState/deallocated')
            }
            Write-CustomHost -Message "Done waiting."
        }
    }
}