Creating an Azure VM with an Empty Data Disk

I was trying to create an Azure virtual machine to run a Domino server online with the following features:

  • Use PowerShell only
  • Latest version of Windows Server
  • Set auto-shutdown
  • Set user credentials on Windows Server
  • Add an empty second disk
  • A virtual network
  • A network security group with predefined rules
  • A public IP address to connect to
  • A storage account for logging and other files
  • Add OMS ID and Key (just in case)
  • Everything in one resource group and location
  • Configuration settings at the top of the script
  • Add comments
  • Write to the screen during processing

I experienced a lot more issues than I ever planned for. I thought that a complete PowerShell script must be available online. However, I could not find one. Thus, I am publishing the one that I created.

The PowerShell Code

Login-AzureRmAccount
Get-AzureRmSubscription | Sort-Object subscriptionName | Select-Object SubscriptionName
Select-AzureRmSubscription -SubscriptionName Pay-As-You-Go

# Declare the variables
$resourceGroup = "myDominoRG1"
$location = "Central US"
$vmName = "myDominoVM1"
$subnetName = 'SubNetDomino1'
$vnetName = "VNetDomino1"
$nsgName = "NSGDomino1"
$VMSize = "Basic_A2"
$storageType = 'Premium_LRS'
$dataDiskName = $vmName + '_datadisk1'
$strNum = 128
[int]$diskSizeInGB = [convert]::ToInt32($strNum, 10)
# Storage Account Name (must be lowercase)
$myStorageName = "mydominostorage1"

# set autoshutdown time for VM
$shutdown_time = "1700"
$shutdown_timezone = "Central Standard Time"

# OMS ID and OMS key
# Leave as is if you do not have an OMS ID and OMS key
$omsId = ""
$omsKey = ""

# Create user object
Write-Host "Create user object"  -ForegroundColor Green
$cred = Get-Credential -Message "Enter a username and password for the virtual machine."

# Create a resource group
Write-Host "Create a resource group"  -ForegroundColor Green
New-AzureRmResourceGroup -Name $resourceGroup -Location $location

# Create a storage account for this resource group
Write-Host "Create a storage account"  -ForegroundColor Green 
New-AzureRMStorageAccount -ResourceGroupName $resourceGroup -Location $Location -AccountName $myStorageName -SkuName Standard_LRS

# Create a subnet configuration
Write-Host "Create a subnet configuration"  -ForegroundColor Green
$subnetConfig = New-AzureRmVirtualNetworkSubnetConfig -Name $subnetName -AddressPrefix 192.168.1.0/24

# Create a virtual network
Write-Host "Create a virtual network"  -ForegroundColor Green
$vnet = New-AzureRmVirtualNetwork -ResourceGroupName $resourceGroup -Location $location `
  -Name $vnetName -AddressPrefix 192.168.0.0/16 -Subnet $subnetConfig

# Create a public IP address and specify a DNS name
Write-Host "Create a public IP address and specify a DNS name"  -ForegroundColor Green
$pip = New-AzureRmPublicIpAddress -ResourceGroupName $resourceGroup -Location $location `
  -Name "mypublicdns$(Get-Random)" -AllocationMethod Static -IdleTimeoutInMinutes 4

# Create an inbound network security group rule for port 3389
Write-Host "Create an inbound network security group rule for port 3389"  -ForegroundColor Green
$rdpRule = New-AzureRmNetworkSecurityRuleConfig -Name "myRDPRule" -Description "Allow RDP" `
    -Access "Allow" -Protocol "Tcp" -Direction "Inbound" -Priority "140" `
    -SourceAddressPrefix * -SourcePortRange * `
    -DestinationAddressPrefix * -DestinationPortRange 3389 

# Create an inbound network security group rule for port 80
Write-Host "Create an inbound network security group rule for port 80"  -ForegroundColor Green
$httprule = New-AzureRmNetworkSecurityRuleConfig -Name "myHTTPRule" -Description "Allow HTTP" `
    -Access "Allow" -Protocol "Tcp" -Direction "Inbound" -Priority "100" `
    -SourceAddressPrefix "Internet" -SourcePortRange * `
    -DestinationAddressPrefix * -DestinationPortRange 80

# Create an inbound network security group rule for port 1352
Write-Host "Create an inbound network security group rule for port 1352"  -ForegroundColor Green
$notesrule = New-AzureRmNetworkSecurityRuleConfig -Name "myIBMNotesRule" -Description "Allow IBM Notes" `
    -Access "Allow" -Protocol "Tcp" -Direction "Inbound" -Priority "120" `
    -SourceAddressPrefix "Internet" -SourcePortRange * `
    -DestinationAddressPrefix * -DestinationPortRange 1352

# Create a network security group
Write-Host "Create a network security group"  -ForegroundColor Green
$nsg = New-AzureRmNetworkSecurityGroup -ResourceGroupName $resourceGroup -Location $location `
  -Name $nsgName -SecurityRules $rdpRule,$httprule,$notesrule

# Create a virtual network card and associate with public IP address and NSG
Write-Host "Create a virtual network card and associate with public IP address and NSG"  -ForegroundColor Green
$nic = New-AzureRmNetworkInterface -Name myNic -ResourceGroupName $resourceGroup -Location $location `
  -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $pip.Id -NetworkSecurityGroupId $nsg.Id

# Create a virtual machine configuration
Write-Host "Create a virtual machine configuration"  -ForegroundColor Green
$vmConfig = New-AzureRmVMConfig -VMName $vmName -VMSize $VMSize | `
Set-AzureRmVMOperatingSystem -Windows -ComputerName $vmName -Credential $cred | `
Set-AzureRmVMSourceImage -PublisherName MicrosoftWindowsServer -Offer WindowsServer -Skus 2016-Datacenter -Version latest | `
Add-AzureRmVMNetworkInterface -Id $nic.Id
Write-Host "Add an empty data disk to the virtual machine configuration"  -ForegroundColor Green
#$vmConfig = Add-AzureRmVMDataDisk -VM $vmConfig -Name $dataDiskName -CreateOption Empty -ManagedDiskId $dataDisk1.Id -Lun 1
$vmConfig = Add-AzureRmVMDataDisk -VM $vmConfig -Name $dataDiskName -DiskSizeInGB $diskSizeInGB -CreateOption Empty -Lun 1

# Create a virtual machine
Write-Host "Create a virtual machine using the virtual machine configuration"  -ForegroundColor Green
New-AzureRmVM -ResourceGroupName $resourceGroup -Location $location -VM $vmConfig

# Set the auto-shutdown time
Write-Host "Set the auto-shutdown time for the virtual machine"  -ForegroundColor Green
$properties = @{
    "status" = "Enabled";
    "taskType" = "ComputeVmShutdownTask";
    "dailyRecurrence" = @{"time" = $shutdown_time };
    "timeZoneId" = $shutdown_timezone;
    "notificationSettings" = @{
        "status" = "Disabled";
        "timeInMinutes" = 30
    }
    "targetResourceId" = (Get-AzureRmVM -ResourceGroupName $resourceGroup -Name $vmName).Id
}

New-AzureRmResource -ResourceId ("/subscriptions/{0}/resourceGroups/{1}/providers/microsoft.devtestlab/schedules/shutdown-computevm-{2}" -f (Get-AzureRmContext).Subscription.Id, $resourceGroup, $vmName) -Location (Get-AzureRmVM -ResourceGroupName $resourceGroup -Name $vmName).Location -Properties $properties -Force

# Setting up WinRM access

# Initialize the data disk

# Install and configure the OMS agent
If ($omsId -ne "") {
    Write-Host "Install and configure the OMS agent"  -ForegroundColor Green
    $PublicSettings = New-Object psobject | Add-Member -PassThru NoteProperty workspaceId $omsId | ConvertTo-Json
    $protectedSettings = New-Object psobject | Add-Member -PassThru NoteProperty workspaceKey $omsKey | ConvertTo-Json

    Set-AzureRmVMExtension -ExtensionName "OMS" -ResourceGroupName $resourceGroup -VMName $vmName `
        -Publisher "Microsoft.EnterpriseCloud.Monitoring" -ExtensionType "MicrosoftMonitoringAgent" `
        -TypeHandlerVersion 1.0 -SettingString $PublicSettings -ProtectedSettingString $protectedSettings `
        -Location $location
}
Write-Host "Finished!"  -ForegroundColor Green

Final Result

One resource group contains all of the resources created by the PowerShell script.

The network security group contains the correct security rules.

A public Internet address is configured.

The virtual machine is configured correctly and it started.

A second data disk was added to the virtual machine.

Update [July 11, 2018]: Follow the step-by-step instructions here to use the D: drive as a data drive on a Windows VM.

Resources

I referenced a number of resources to create this script. Below are a few of the important ones.

Create a fully configured virtual machine with PowerShell

https://docs.microsoft.com/en-us/azure/virtual-machines/scripts/virtual-machines-windows-powershell-sample-create-vm?toc=%2fpowershell%2fmodule%2ftoc.json

Create an Operations Management Suite monitored VM with PowerShell

https://docs.microsoft.com/en-us/azure/virtual-machines/scripts/virtual-machines-windows-powershell-sample-create-vm-oms?toc=%2fpowershell%2fmodule%2ftoc.json

Add-AzureRmVMDataDisk

https://docs.microsoft.com/en-us/powershell/module/azurerm.compute/add-azurermvmdatadisk

New-AzureRmVM

https://docs.microsoft.com/en-us/powershell/module/azurerm.compute/new-azurermvm?view=azurermps-6.3.0

Attach a data disk to a Windows VM using PowerShell

https://docs.microsoft.com/en-us/azure/virtual-machines/windows/attach-disk-ps

 

Next Steps

Initialize the data disk and install the Domino server software. As it is now, the second data disk can be used for any purpose.

I want to have a data disk in storage that has the Domino server software installed; but not configured. Then I can attach it to the VM. That would save time for multiple virtual machines.

I want to use a VPN connection to the virtual network. The public IP address should be VPN gateway. The virtual machines would not be exposed to the Internet directly. All connections would go through the VPN gateway.

I should be using an Azure Resource Manager (ARM) template. I want to deploy the resources consistently and repeatedly.