Public/Deploy-B42VM.ps1

function Deploy-B42VM {
    <#
        .SYNOPSIS
        Deploys a VM.
        .DESCRIPTION
        The Deploy-B42VM function serves as a one touch deploy point for an Azure Virtual Machine
        .EXAMPLE
        Deploy-B42VM
        .NOTES
        You need to run this function after establishing an AzureRm context using Login-AzureRmAccount
    #>

    [CmdletBinding()]
    param (
        # The destination Resource Group Name
        [Parameter(Mandatory=$true)]
        [string] $ResourceGroupName,

        # The destination Azure region
        [Parameter(Mandatory=$false)]
        [string] $Location,

        # Parameters used for VM creation
        [Parameter(Mandatory = $false)]
        [System.Collections.Specialized.OrderedDictionary] $VMParameters = [ordered]@{},

        # If true, a Public IP and NSG will be created for the VM
        [Parameter(Mandatory = $false)]
        [switch] $IncludePublicInterface,

        # If true, the vm will use linux specific configuraiton settings. If false, the vm will use windows specific configuration settings.
        [Parameter (Mandatory = $false)]
        [switch] $IsLinux
    )

    begin {
        Write-Verbose ("{0} started at {1} " -f $MyInvocation.MyCommand, (Get-Date).ToString())
    }

    process {
        $accumulatedDeployments = @()
        # The parameters in VirtualNetworkParameters are required. If not provided, create some defaults.
        if (!($VMParameters.Contains("vnetResourceGroupName") -and $VMParameters.Contains("vnetName") -and $VMParameters.Contains("subnetName"))) {
            $vnetParams = Get-B42TemplateParameters -Templates @("VNet")
            $subnetParams = Get-B42TemplateParameters -Templates @("Subnet")
            $accumulatedDeployments += Deploy-B42VNet -ResourceGroupName $ResourceGroupName -Location $Location -VNetParameters $vnetParams -Subnets @($subnetParams)
            # Carry along these values to the VMDeployment.
            $VMParameters.Add("vnetResourceGroupName", $ResourceGroupName)
            $VMParameters.Add("vnetName", $vnetParams.vnetName)
            $VMParameters.Add("subnetName", $subnetParams.subnetName)
        }

        if (!($VMParameters.Contains("keyVaultResourceGroupName") -and $VMParameters.Contains("keyVaultName"))) {
            $currentContext = Get-AzureRmContext
            $TenantID = $currentContext.Tenant.Id
            $ObjectID = (Get-AzureRmADUser -StartsWith $currentContext.Account.Id).Id
            $kvParams = @{
                keyVaultTenantID                     = $TenantID
                keyVaultAccessPolicies               = @((Get-B42KeyVaultAccessPolicy -ObjectID $ObjectID -TenantID $TenantID))
                keyVaultEnabledForDeployment         = $true
                keyVaultEnabledForTemplateDeployment = $true
            }
            $keyVaultResult = New-B42Deployment -ResourceGroupName $ResourceGroupName -Location "$Location" -Templates @("KeyVault") -TemplateParameters $kvParams
            $accumulatedDeployments += $keyVaultResult
            # Carry along these values to the VMDeployment.
            $VMParameters.Add("keyVaultResourceGroupName", $ResourceGroupName)
            $VMParameters.Add("keyVaultName", $keyVaultResult.Parameters.keyVaultName.Value)

            # TODO Linux.
            $certPath = ("{0}\Blue42VM.pfx" -f (Convert-Path -Path ".\"))
            $certForms = Get-B42CertificateForms -CertificatePath $certPath -DomainNames @("testing.local")
            Remove-Item $certPath

            $null = Add-Secret -KeyVaultName $keyVaultResult.Parameters.keyVaultName.Value -SecretName "CertPassword" -SecretValue $certForms.Password
            $certSecret = Add-Secret -KeyVaultName $keyVaultResult.Parameters.keyVaultName.Value -SecretName "Cert" -SecretValue $certForms.JsonArray
            $VMParameters.Add("vmCertificateSecretUrl", $certSecret.Id)

            # Add the admin user and password.
            # Should the VM just reference the password in the keyVault?
            $aUser = "azdam"
            $aPass = (New-B42Password)
            $VMParameters.Add("vmAdminUsername", $aUser)
            $VMParameters.Add("vmAdminPassword", $aPass)
            Add-Secret -KeyVaultName $keyVaultResult.Parameters.keyVaultName.Value -SecretName "AdminUsername" -SecretValue $aUser
            Add-Secret -KeyVaultName $keyVaultResult.Parameters.keyVaultName.Value -SecretName "AdminPassword" -SecretValue $aPass
        }
        # Create a NIC here
        $templates = @("NetworkInterface")
        $nicParams = Get-B42TemplateParameters -Templates $templates -TemplateParameters $VMParameters
        if ($IncludePublicInterface) {
            # Ok. This should probably be more simple. Not sure that the $pipnsgResult order is guaranteed. The alternative
            # may be simply to Test-B42Deployment to combine the parameter sets?
            $pipnsgParameters = Get-B42TemplateParameters -Templates @("PublicIP", "NSG") -TemplateParameters $nicParams
            $list = Get-NSGList -IsLinux:$IsLinux
            $pipnsgParameters.nsgSecurityRules = $list
            $accumulatedDeployments += New-B42Deployment -ResourceGroupName $ResourceGroupName -Location "$Location" -Templates @("PublicIP", "NSG") -TemplateParameters $pipnsgParameters
            $nicParams.publicIPName = $pipnsgParameters.publicIPName
            $nicParams.nsgName = $pipnsgParameters.nsgName
        }
        $nicDeploymentResult = New-B42Deployment -ResourceGroupName $ResourceGroupName -Location "$Location" -Templates $templates -TemplateParameters $nicParams
        $accumulatedDeployments += $nicDeploymentResult
        $VMParameters.Add("networkInterfaceName", $nicDeploymentResult.Parameters.networkInterfaceName.Value)

        # TODO: More tokens for resourceid
        if ($VMParameters.Contains("imageName")) {
            $VMParameters.Add("vmImagePublisher", "")
            $VMParameters.Add("vmImageOffer", "")
            $VMParameters.Add("vmImageSKU", "")
        }

        $deploymentResult = New-B42Deployment -ResourceGroupName $ResourceGroupName -Location "$Location" -Templates @("WinVM") -TemplateParameters $VMParameters
        $accumulatedDeployments += $deploymentResult
        $vmName = $deploymentResult.Parameters.vmName.Value
        if ([string]::IsNullOrEmpty($vmName)) {throw "Failed to obtain VM name"}

        if($deploymentResult.Parameters.vmIdentity.Value -eq "SystemAssigned"){
            # Find the Managed Service Identity PrincipalId and grant it permission to query the secrets.
            $vmInfoPS = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $vmName
            if (![string]::IsNullOrEmpty($vmInfoPS.Identity.PrincipalId)) {
                Set-AzureRmKeyVaultAccessPolicy -VaultName $VMParameters.keyVaultName -PermissionsToSecrets get, list -ObjectId $vmInfoPS.Identity.PrincipalId
            }
        }

        # TODO: Return a report card here instead.
        $accumulatedDeployments
    }

    end {
        Write-Verbose ("{0} ended at {1} " -f $MyInvocation.MyCommand, (Get-Date).ToString())
    }
}