Functions/New-AzureV2VMFromGallaryImage.ps1

Function New-AzureV2VMFromGallaryImage
{

<#
  .SYNOPSIS
  Creating virtual machine(s) from gallery image with one line.
  
  .DESCRIPTION
  This cmdlet will create a single or numerous virtual machines from gallery image with just one line.
  
  .PARAMETER SubscriptionId
  Subscription ID for the subscription that virtual machine(s) is on. Required
    
  .PARAMETER rgName
  Resource group where the resources will be created. Required

  .PARAMETER vmNames
  Name or names of the virtual machine(s) to be created. Required

  .PARAMETER location
  Location where the Azure resources will be created.

  .PARAMETER saName
  Name of the storage account name to use if you want to use un-managed disk. Note: If storage account doesn't exist, cmdlet will create a unique storage account.

  .PARAMETER vnetName
  Name of the virtual network that virtual machine will be on.

  .PARAMETER vmSize
  Size of the new virtual machine that is been created Example: Standard_A0 See information in link https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-sizes/.

  .PARAMETER WindowsSku
  Windows SKU to use to create the virtual machine(s).

  .PARAMETER nsgName
  Specify a NIC NSG that you will like machine to be on. If not specified a Windows default NSG will be used/created automatically.

  .PARAMETER VMUser
  Username that will be used for the Windows configuration.

  .PARAMETER VMPass
  Password that will be used for the Windows configuration. If not specified a strong random password will be generated and used.

  .NOTES
  Author : Hannel Hazeley - hhazeley@outlook.com

  .LINK
  https://github.com/hhazeley/HannelsToolBox/blob/master/Functions/New-AzureV2VMFromGallaryImage.ps1

  .EXAMPLE
  New-AzureV2VMFromGallaryImage -SubscriptionId 1d6737e7-4f6c-4e3c-8cd4-996b6f003d0e -rgName DVideoRG1 -vmNames DV1-DPBSV1-001

  This will create virtual machine using all cmdlet default configuration.
  #>


[cmdletbinding()]
Param (
    [Parameter(Mandatory=$true)]
    $SubscriptionId,
    [Parameter(Mandatory=$true)]
    $rgName,
    [Parameter(Mandatory=$true)]
    $vmNames,
    [ValidateSet('eastasia','southeastasia','centralus','eastus','eastus2','westus','northcentralus','southcentralus','northeurope','westeurope','japanwest','japaneast','brazilsouth','australiaeast','australiasoutheast','southindia','centralindia','westindia','canadacentral','canadaeast','uksouth','ukwest','westcentralus','westus2','koreacentral','koreasouth')]
    $location,
    $saName,
    $vnetName,
    [ValidateSet('Standard_DS1_v2','Standard_DS2_v2','Standard_DS3_v2','Standard_DS4_v2','Standard_DS5_v2','Standard_DS11_v2','Standard_DS12_v2','Standard_DS13-2_v2','Standard_DS13-4_v2','Standard_DS13_v2','Standard_DS14-4_v2','Standard_DS14-8_v2','Standard_DS14_v2','Standard_DS15_v2','Standard_F1s','Standard_F2s','Standard_F4s','Standard_F8s','Standard_F16s','Standard_A0','Standard_A1','Standard_A2','Standard_A3','Standard_A5','Standard_A4','Standard_A6','Standard_A7','Basic_A0','Basic_A1','Basic_A2','Basic_A3','Basic_A4','Standard_D1_v2','Standard_D2_v2','Standard_D3_v2','Standard_D4_v2','Standard_D5_v2','Standard_D11_v2','Standard_D12_v2','Standard_D13_v2','Standard_D14_v2','Standard_D15_v2','Standard_DS1','Standard_DS2','Standard_DS3','Standard_DS4','Standard_DS11','Standard_DS12','Standard_DS13','Standard_DS14','Standard_B1ms','Standard_B1s','Standard_B2ms','Standard_B2s','Standard_B4ms','Standard_B8ms','Standard_D2_v3','Standard_D4_v3','Standard_D8_v3','Standard_D16_v3','Standard_D32_v3','Standard_D64_v3','Standard_D2s_v3','Standard_D4s_v3','Standard_D8s_v3','Standard_D16s_v3','Standard_D32s_v3','Standard_D64s_v3','Standard_E2_v3','Standard_E4_v3','Standard_E8_v3','Standard_E16_v3','Standard_E32_v3','Standard_E64_v3','Standard_E2s_v3','Standard_E4s_v3','Standard_E8s_v3','Standard_E16s_v3','Standard_E32-8s_v3','Standard_E32-16s_v3','Standard_E32s_v3','Standard_E64-16s_v3','Standard_E64-32s_v3','Standard_E64s_v3','Standard_G1','Standard_G2','Standard_G3','Standard_G4','Standard_G5','Standard_GS1','Standard_GS2','Standard_GS3','Standard_GS4','Standard_GS4-4','Standard_GS4-8','Standard_GS5','Standard_GS5-8','Standard_GS5-16','Standard_L4s','Standard_L8s','Standard_L16s','Standard_L32s','Standard_A8','Standard_A9','Standard_A10','Standard_A11','Standard_H8','Standard_H16','Standard_H8m','Standard_H16m','Standard_H16r','Standard_H16mr')]
    $vmSize,
    [ValidateSet('2008-R2-SP1','2008-R2-SP1-smalldisk','2012-Datacenter','2012-Datacenter-smalldisk','2012-R2-Datacenter','2012-R2-Datacenter-smalldisk','2016-Datacenter','2016-Datacenter-smalldisk')]
    $WindowsSku,
    $nsgName,
    $avsetName,
    $VMUser,
    $VMPass
)

$ErrorActionPreference = "SilentlyContinue"
$WarningPreference = "SilentlyContinue"

If ($location -eq $null)
{
$location = "westus2"
}
If ($vnetName -eq $null)
{
$vnetName = $rgName+"-VNet1"
}
If ($vmSize -eq $null)
{
$vmSize = "Standard_B2ms"
}
If ($WindowsSku -eq $null)
{
$WindowsSku = "2012-R2-Datacenter-smalldisk"
}
If ($StorageSku -eq $null)
{
$StorageSku = "Standard_LRS"
}
If ($SubnetAddressPrefix -eq $null)
{
$SubnetAddressPrefix = "10.0.0.0/26"
}
If ($VNetAddressPrefix -eq $null)
{
$VNetAddressPrefix = "10.0.0.0/24"
}

#Function for error checks
Function ErrorCheck{
If ($errorck -ne $null)
{
Write-host
Write-host -ForegroundColor Red "ERROR: " -NoNewline
Write-Host -ForegroundColor Red $errorck
if ($nic1created.IsPresent)
{
Write-Host -ForegroundColor Yellow -BackgroundColor Black "Rolling back..... Removing Network Interface $ipName1"
Remove-AzureRmNetworkInterface -Name $ipName1 -ResourceGroupName $rgName -Force | Out-Null
}
if ($pip1created.IsPresent)
{
Write-Host -ForegroundColor Yellow -BackgroundColor Black "Rolling back..... Removing Public IP $ipName1"
Remove-AzureRmPublicIpAddress -Name $ipName1 -ResourceGroupName $rgName -Force | Out-Null
}
if ($nsgcreated.IsPresent)
{
Write-Host -ForegroundColor Yellow -BackgroundColor Black "Rolling back..... Removing NSG $vmnsgName"
Remove-AzureRmNetworkSecurityGroup -Name $vmnsgName -ResourceGroupName $rgName -Force | Out-Null
}
if ($avsetcreated.IsPresent)
{
Write-Host -ForegroundColor Yellow -BackgroundColor Black "Rolling back..... Removing Availability Set $avsetName"
Remove-AzureRmAvailabilitySet -Name $avsetName -ResourceGroupName $rgName -Force | Out-Null
}
if ($VNetcreated.IsPresent)
{
Write-Host -ForegroundColor Yellow -BackgroundColor Black "Rolling back..... Removing Virtual Network $vnetName"
Remove-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName -Force | Out-Null
}
if ($sacreated.IsPresent)
{
Write-Host -ForegroundColor Yellow -BackgroundColor Black "Rolling back..... Removing Storage Account $saName"
Remove-AzureRmStorageAccount -Name $saName -ResourceGroupName $rgName -Force | Out-Null
}
if ($rgcreated.IsPresent)
{
Write-Host -ForegroundColor Yellow -BackgroundColor Black "Rolling back..... Removing Resource Group $rgName"
Remove-AzureRmResourceGroup -Name $rgName -Force | Out-Null
}
Write-Host "______________________________________________________________________"
Write-Host -ForegroundColor Red "Script aborted and actions rolled back, see above error."
Write-Host "______________________________________________________________________"
Break
}
}

#Set subscription
$hout = Select-AzureRmSubscription -SubscriptionId $SubscriptionId -ErrorVariable errorck
ErrorCheck

Write-Host "______________________________________________________________________"
Write-Host -ForegroundColor Cyan "Starting deployment"
Write-Host "______________________________________________________________________"
Write-Host 

#Check for and/or created Azure Resource Group
$rgNameValidation = Get-AzureRmResourceGroup -Name $rgName 
if ($rgNameValidation -eq $null)
{
Write-Host -ForegroundColor Green "Creating Resource Group $rgName"
$rg = New-AzureRmResourceGroup -Name $rgName -location $location -Force -ErrorVariable errorck
ErrorCheck
[Switch]$rgcreated = $true
}
Else
{
$rgLocation = $rgNameValidation.Location
If ($rgLocation -ne $location)
{
Write-Host -ForegroundColor Yellow -BackgroundColor Black "Resource Group location is different from specified location, resource will be created using same location as Resource Group ($rgLocation)."
$location = $rgLocation
}
}

If ($avsetName -ne $null)
{
#Prepare availability for virtual machine
$avsetValidation = Get-AzureRmAvailabilitySet -ResourceGroupName $rgName -Name $avsetName
if ($avsetValidation -eq $null -and $saName -eq $null)
{
#Creating availability set
Write-Host -ForegroundColor Green "Creating new managed availability set $avsetName"
$avset = New-AzureRmAvailabilitySet -Location $location -Name $avsetName -ResourceGroupName $rgName -Sku Aligned -PlatformUpdateDomainCount 5 -PlatformFaultDomainCount 2 -ErrorVariable errorck
ErrorCheck
[Switch]$avsetcreated = $true
}
elseif ($avsetValidation -eq $null -and $saName -ne $null)
{
#Creating availability set
Write-Host -ForegroundColor Green "Creating new availability set $avsetName"
$avset = New-AzureRmAvailabilitySet -Location $location -Name $avsetName -ResourceGroupName $rgName -ErrorVariable errorck
ErrorCheck
[Switch]$avsetcreated = $true
}
Else
{
Write-Host -ForegroundColor Green "Availability set $avsetName exist"
$avset = Get-AzureRmAvailabilitySet -ResourceGroupName $rgName -Name $avsetName
if ($avset.Aligned -eq $true -and $saName -ne $null)
{
  $errorck = "VM with managed disks to non-managed Availability Set or addition of a VM with blob based disks to managed Availability Set is not supported."
  ErrorCheck
}
if ($avset.Aligned -eq $false -and $saName -eq $null)
{
  $errorck = "VM with managed disks to non-managed Availability Set or addition of a VM with blob based disks to managed Availability Set is not supported."
  ErrorCheck
}
}
}

If ($saName -ne $null)
{

#Prepare storage account for virtual machine
$storageAccValidation = Get-AzureRmStorageAccount -ResourceGroupName $rgName -AccountName $saName
if ($storageAccValidation -eq $null)
{

# Create a new storage account for the VM
$checkAvailability = (Get-AzureRmStorageAccountNameAvailability -Name $saname).NameAvailable
If ($checkAvailability -eq $false)
{
$rnum = Get-Random -Minimum 1000 -Maximum 9999
$userID = (Get-AzureRmContext).Account.Id
$userID = $userID.Substring(0,3)
if ($rgName.Length -gt 14)
{
$rgNamestr = $rgName.Substring(0,14)
}
else
{
$rgNamestr = $rgName
}
$newsaName = $rgNamestr+"str"+$userID+$rnum 
$newsaName = $newsaName -replace '[^a-zA-Z0-9]', ''
$newsaName = $newsaName.ToLower()
Write-Host  -ForegroundColor  Yellow -BackgroundColor Black "Storage account name $saname not available, a unique storage account name $newsaname was created instead"
$saName = $newsaname
}

Write-Host -ForegroundColor Green "Creating Storage Account $saName"
$storageAcc = New-AzureRmStorageAccount -Location $location -Name $saName -ResourceGroupName $rgName -SkuName $StorageSku -Kind Storage -ErrorVariable errorck
ErrorCheck
[Switch]$sacreated = $true
}
Else
{
$storageAcc = Get-AzureRmStorageAccount -ResourceGroupName $rgName -AccountName $saName
}
}

$vnetvalidation = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
If ($vnetvalidation -eq $null)
{
Write-Host -ForegroundColor Green "Creating Virtual Network $vnetName"
$Subnet =New-AzureRmVirtualNetworkSubnetConfig -AddressPrefix $SubnetAddressPrefix -Name Subnet1 -ErrorVariable errorck
ErrorCheck
$vnet = New-AzureRmVirtualNetwork -AddressPrefix $VNetAddressPrefix -Location $location -Name $vnetName -ResourceGroupName $rgName -Force -Subnet $Subnet -ErrorVariable errorck
ErrorCheck
[Switch]$VNetcreated = $true
}
Else
{
$vnet = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
}

Foreach ($vmName in $vmNames)
{
$vmNameValidation = Get-AzureRmVM -ResourceGroupName $rgName -Name $vmName
if ($vmNameValidation -ne $null)
{
Write-Host
Write-Host -ForegroundColor Red "Cannot create Virtual Machine, $vmName already exist."
Write-Host
Break
}
Write-Host -ForegroundColor Green "Starting deployment for Virtual Machine $vmName."

If ($VMUser -eq $null)
{
$VMUser = "VMAdmin"
}

If ($VMPass -eq $null)
{
[Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null
$VMPass = [System.Web.Security.Membership]::GeneratePassword(15,2)
}

$VMPWord = ConvertTo-SecureString -String "$VMPass" -AsPlainText -Force
$cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $VMUser, $VMPWord

#Getting existing NSG in resource group
If ($nsgName -eq $null)
{
$vmnsgName = $vmName+"-nsg"
}
Else
{
$vmnsgName = $nsgName
}
$VNetworkSecurityGroup = (Get-AzureRmNetworkSecurityGroup -ResourceGroupName $rgName).Name
#Validating Default NSG exists
If ($VNetworkSecurityGroup -notcontains "$vmnsgName")
{
#Creating Default Windows NSG
Write-Host -ForegroundColor Green "Creating Network Security Groups $vmnsgName"
$NSGRule = New-AzureRmNetworkSecurityRuleConfig -Name default-allow-rdp -Access Allow -Description "Allowing RDP connection" -DestinationAddressPrefix * -DestinationPortRange 3389 -Direction Inbound -Priority 1000 -Protocol Tcp -SourceAddressPrefix * -SourcePortRange *
New-AzureRmNetworkSecurityGroup -Location $location -Name $vmnsgName -ResourceGroupName $rgName -SecurityRules $NSGRule | Out-Null
[Switch]$nsgcreated = $true
ErrorCheck
}

#Setting NSG to windows default NSG, since its not provided
$nsg = Get-AzureRmNetworkSecurityGroup -ResourceGroupName $rgName -Name $vmnsgName

#Set the VM name and size
#Use "Get-Help New-AzureRmVMConfig" to know the available options for -VMsize
Write-Host -ForegroundColor Green "Creating Virtual Machine $vmName configuration"
If ($avsetName -eq $null)
{
 $vm = New-AzureRmVMConfig -VMName $vmName -VMSize $vmSize -LicenseType "Windows_Server" 
}
else 
{
  $AvailabilitySetId = $avset.Id
  $vm = New-AzureRmVMConfig -VMName $vmName -VMSize $vmSize -LicenseType "Windows_Server" -AvailabilitySetId $AvailabilitySetId
}

#Set the Windows operating system configuration and add the NIC
$computerName = $vmName
$vm = Set-AzureRmVMOperatingSystem -VM $vm -Windows -ComputerName $computerName -Credential $cred -ProvisionVMAgent -EnableAutoUpdate 
$vm = Set-AzureRmVMSourceImage -VM $vm -PublisherName MicrosoftWindowsServer -Offer WindowsServer -Skus $WindowsSku -Version "latest" -ErrorVariable errorck
ErrorCheck

$rnum = Get-Random -Minimum 100 -Maximum 999
$ipName1 = $vmName + $rnum
Write-Host -ForegroundColor Green "Creating Public IP $ipName1"
$pip1 = New-AzureRmPublicIpAddress -Name $ipName1 -Location $location -ResourceGroupName $rgName -AllocationMethod Dynamic
[Switch]$pip1created = $true
Write-Host -ForegroundColor Green "Creating Network Interface $ipName1"
$nic1 = New-AzureRmNetworkInterface -Name $ipName1 -ResourceGroupName $rgName -Location $location -PublicIpAddressId $pip1.Id -SubnetId $vnet.Subnets[0].Id -NetworkSecurityGroupId $nsg.Id
[Switch]$nic1created = $true
Write-Host -ForegroundColor Green "Adding Network Interface $ipName1 to Virtual Machine $vmName"
$vm = Add-AzureRmVMNetworkInterface -VM $vm -Id $nic1.Id -Primary

# Set OSDisk Name
$diskdate = Get-Date -Format yyyyMMddHHmmss
$osDiskName  = $vmName +"-OSDisk"+$diskdate

If ($saName -eq $null)
{
#You set this variable when you uploaded the VHD
$vm = Set-AzureRmVMOSDisk -VM $vm -Name $osDiskName -CreateOption FromImage -Windows -StorageAccountType Standard_LRS
}
else
{
#Create the OS disk URI
$osDiskUri = '{0}vhds/{1}.vhd' -f $storageAcc.PrimaryEndpoints.Blob.ToString(), $osDiskName

#You set this variable when you uploaded the VHD
$vm = Set-AzureRmVMOSDisk -VM $vm -Name $osDiskName -VhdUri $osDiskUri -CreateOption FromImage -Windows
}
#Create the new VM
Write-Host -ForegroundColor Green "Creating Virtual Machine $vmName"
$newVM = New-AzureRmVM -ResourceGroupName $rgName -Location $location -VM $vm -ErrorVariable errorck
ErrorCheck

$vmIP = (Get-AzureRmPublicIpAddress -Name $ipName1 -ResourceGroupName $rgName).IpAddress
Write-Host "______________________________________________________________________"
Write-Host -ForegroundColor Green "Virtual Machine $vmName deployment completed."
Write-Host -ForegroundColor Green "Username: " -NoNewline
Write-Host -ForegroundColor White $VMUser -NoNewline
Write-Host -ForegroundColor Green " Password: " -NoNewline
Write-Host -ForegroundColor White $VMPass -NoNewline
Write-Host -ForegroundColor Green " PublicIP: " -NoNewline
Write-Host -ForegroundColor White $vmIP
Write-Host "______________________________________________________________________"
Write-Host 
}

Write-Host "______________________________________________________________________"
Write-Host -ForegroundColor Cyan "Deployment Completed"
Write-Host "______________________________________________________________________"
}

Export-ModuleMember -Function New-AzureV2VMFromGallaryImage