Export/New-ScaleSetImage.ps1
function Global:New-ScaleSetImage { [CmdletBinding()] <# .SYNOPSIS Creates a new Application Server, installs Business Central, sys-preps it and saves it as a Scale Set Source .DESCRIPTION This CmdLet will create a new VM, initialize it (install this and other modules to it), download the desired Business Central DVD and install it locally. Afterwards it will generalize the created VM and set it as an Image to be used for future ScaleSets #> param( [Parameter(Mandatory = $true)] [string] $ResourceGroupName, [Parameter(Mandatory = $true)] [string] $ResourceLocation, [Parameter(Mandatory = $true)] [string] $Name, [Alias("Version")] [Parameter(Mandatory = $false)] [string] $BCVersion, [Alias("CumulativeUpdate")] [Parameter(Mandatory = $false)] [string] $BCCumulativeUpdate, [Alias("Language")] [Parameter(Mandatory = $false)] [string] $BCLanguage, [Alias("VirtualNetworkName")] [Parameter(Mandatory = $true)] [string] $VNetName, [Parameter(Mandatory = $true)] [string] $VMName, [Parameter(Mandatory = $true)] [string] $VMImagePublisher, [Parameter(Mandatory = $true)] [string] $VMImageOffer, [Parameter(Mandatory = $true)] [string] $VMImageSku, [Parameter(Mandatory = $true)] [string] $VMSize, [Parameter(Mandatory = $true)] [PSCredential] $VMCredentials, [Parameter(Mandatory = $true)] [int] $VMDiskSizeInGb, [Parameter(Mandatory = $true)] [string] $VMStorageAccountType, [Parameter(Mandatory = $true)] [string] $VMDataDiskName, [Alias("NetworkInterfaceName")] [Parameter(Mandatory = $true)] [string] $NicName, [Alias("NetworkInterfacePrivateIP")] [Parameter(Mandatory = $false)] [string] $NicPrivateIP, [Parameter(Mandatory = $false)] [string] $SubnetName, [Alias("PublicIPName")] [Parameter(Mandatory = $false)] [string] $PipName, [Alias("PublicIPDomainNameLabel")] [Parameter(Mandatory = $false)] [string] $PipDnsLabel, [Parameter(Mandatory = $false)] [string] $GalleryName, [Parameter(Mandatory = $false)] [string] $GalleryDefinitionName, [Parameter(Mandatory = $false)] [string] $GalleryPublisher, [Parameter(Mandatory = $false)] [string] $GalleryOffer, [Parameter(Mandatory = $false)] [string] $GallerySku ) process { $image = Get-AzImage -ResourceGroupName $ResourceGroupName -ImageName $Name -ErrorAction SilentlyContinue if ($image) { Write-CustomHost -Message "Image $Name already exists. Stopping here." return } # Copy arguments for NIC creation from parent call $VMArguments = @{ } foreach ($param in $PsBoundParameters.GetEnumerator() | Where-Object { $_.Key -notlike "BC*" }) { $VMArguments.Add($param.Key, $param.Value) } # Create new VM (as Application Server), might be a job, might be a VM-object (if VM already exists) $vm = New-CustomAzVm @VMArguments -AsJob if ($vm.GetType().ToString() -ne "Microsoft.Azure.Commands.Compute.Models.PSVirtualMachine") { # Means: Job is currently running / VM is currently being deploy # use Write-CustomHost -Message "Receiving job..." $vm = Receive-Job -Job $vm -Wait Write-CustomHost -Message "Job received" # to get the VM-object } # Assign created VM the Contributor role for the resource group (to be able to read data from storage account) # TODO: Check if lesser role is a possibility Write-CustomHost -Message "Assigning access role to managed identity of VM..." $vm = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VMName New-AzRoleAssignment -ObjectId $vm.Identity.PrincipalId -RoleDefinitionName Contributor -ResourceGroupName $ResourceGroupName | Out-Null Write-CustomHost -Message "Done." $bcVersionArgs = @{ } foreach ($param in $PsBoundParameters.GetEnumerator() | Where-Object { $_.Key -like "BC*" }) { $bcVersionArgs.Add($param.Key.Remove(0, 2), $param.Value) } Write-CustomHost -Message "Sleeping for 2 minutes to give the VM a chance to completely start (network might be unavailable if we start right away)..." Start-Sleep -Seconds (2 * 60) Write-CustomHost -Message "Done sleeping." Write-CustomHost -Message "Attempting to Install module on VM..." Submit-ScriptToVmAndExecute -ResourceGroupName $ResourceGroupName -ResourceLocation $ResourceLocation -VMName $VMName -ScriptBlockName InstallD365Module Write-CustomHost -Message "Attempting to initialize some basics on VM..." Submit-ScriptToVmAndExecute -ResourceGroupName $ResourceGroupName -ResourceLocation $ResourceLocation -VMName $VMName -ScriptBlockName InitVM Write-CustomHost -Message "Attempting to download BC to VM..." Submit-ScriptToVmAndExecute -ResourceGroupName $ResourceGroupName -ResourceLocation $ResourceLocation -VMName $VMName -ScriptBlockName DownloadBC -RunParameter $bcVersionArgs Write-CustomHost -Message "Attempting to install BC to VM..." Submit-ScriptToVmAndExecute -ResourceGroupName $ResourceGroupName -ResourceLocation $ResourceLocation -VMName $VMName -ScriptBlockName InstallBC return Write-CustomHost -Message "Attempting to generalize VM..." Submit-ScriptToVmAndExecute -ResourceGroupName $ResourceGroupName -ResourceLocation $ResourceLocation -VMName $VMName -ScriptBlockName GeneralizeVM return Write-CustomHost -Message "Stopping VM..." Stop-AzVm -ResourceGroupName $ResourceGroupName -Name $VMName -Force | Out-Null Write-CustomHost -Message "Generalizing VM..." Set-AzVM -ResourceGroupName $ResourceGroupName -Name $VMName -Generalized | Out-Null Write-CustomHost -Message "Preparing VM-image..." $vm = Get-AzVM -Name $VMName -ResourceGroupName $ResourceGroupName $image = New-AzImageConfig -Location $ResourceLocation -SourceVirtualMachineId $vm.ID New-AzImage -Image $image -ImageName $Name -ResourceGroupName $ResourceGroupName | Out-Null Write-CustomHost -Message "Done." if (-not([string]::IsNullOrEmpty($GalleryName))){ Write-CustomHost -Message "Adding Image to Gallery..." Add-CustomImageToGallery -ResourceGroupName $ResourceGroupName -ResourceLocation $ResourceLocation ` -GalleryName $GalleryName -GalleryDefinitionName $GalleryDefinitionName -GalleryPublisher $GalleryPublisher ` -GalleryOffer $GalleryOffer -GallerySku $GallerySku -SourceImageName $Name } } } Export-ModuleMember -Function New-ScaleSetImage |