Create a Windows Server virtual machine with PowerShell
Tags: azure, powershell, vm
Published: 2020-06-07 07:42:22

In today blog post we are going to create and use an Azure VM with powershell, This blog post also shows you the steps to:

- Connect to the virtual machine with a remote client.
- Clean up resources.

### Install and import AzureRM

In order to use and execute the below commands we need to install and import the AzureRM powershell module if we don't already have it, if you already have it you can skip this section.

PS: You need elevated privileges to install modules from PowerShell Gallery

<pre>
<code class="language-powershell line-numbers">
Install-Module -Name AzureRM -AllowClobber
</code></pre>

By default, the PowerShell gallery is not configured as a trusted repository for PowerShellGet. The first time you use PSGallery, the following message is displayed:

<pre><code class="language-powershell line-numbers">
Untrusted repository

You are installing the modules from an untrusted repository. If you trust this repository, change
its InstallationPolicy value by running the Set-PSRepository cmdlet.

Are you sure you want to install the modules from 'PSGallery'?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend [?] Help (default is "N"):
</code></pre>

So, don't worry about this message.

Once installed, you can import AzureRM by running the following command:

<pre><code class="language-powershell line-numbers">
Import-Module AzureRM
</code></pre>

Finnaly, to finish with this section we need to connect to Azure account, simply execute this command and you we be prompted:

<pre><code class="language-powershell line-numbers">
# Connect to Azure with an interactive dialog for sign-in
Connect-AzureRmAccount
</code></pre>

<img src="https://mselmi.net/wp-content/uploads/2020/06/Az_login_password-281x300.png" alt="" /> <img src="https://mselmi.net/wp-content/uploads/2020/06/Az_login-280x300.png" alt="" />

### Create a resource group

A resource group is a logical container in which Azure resources are deployed and managed.
From your SDK, run the following code block to create a resource group:

<pre><code class="language-powershell line-numbers">
# Create variables to store the location and resource group names.
$location = "francecentral"
$ResourceGroupName = "resource-group-1"

New-AzureRmResourceGroup -Name $ResourceGroupName -Location $location
</code></pre>

### Create storage resources

Create a storage account to store the output of boot diagnostics.

<pre><code class="language-powershell line-numbers">
# Create variables to store the storage account name and the storage account SKU information
$StorageAccountName = "msstorage01"
$SkuName = "Standard_LRS"

# Create a new storage account
$StorageAccount = New-AzureRMStorageAccount `
  -Location $location `
  -ResourceGroupName $ResourceGroupName `
  -Type $SkuName `
  -Name $StorageAccountName

Set-AzureRmCurrentStorageAccount `
  -StorageAccountName $storageAccountName `
  -ResourceGroupName $resourceGroupName
</code></pre>

<h3>Create networking resources</h3>

Create a VNet (virtual network), subnet, and a public IP address. Creating these Azure resources help us providing the network connectivity to our VM.

<pre><code class="language-powershell line-numbers">
# Create a the subnet configuration
$subnetConfig = New-AzureRmVirtualNetworkSubnetConfig `
  -Name subNet-1 `
  -AddressPrefix 192.168.1.0/24
</code></pre>

### Create the virtual network
<pre><code class="language-powershell line-numbers">
$vnet = New-AzureRmVirtualNetwork `
  -ResourceGroupName $ResourceGroupName `
  -Location $location `
  -Name vNet-1 `
  -AddressPrefix 192.168.0.0/16 `
  -Subnet $subnetConfig
</code></pre>

### Create a public IP address and specify a DNS name
<pre><code class="language-powershell line-numbers">
$publicip = New-AzureRmPublicIpAddress `
  -ResourceGroupName $ResourceGroupName `
  -Location $location `
  -AllocationMethod Static `
  -IdleTimeoutInMinutes 4 `
  -Name "mypublicdns$(Get-Random)"
</code></pre>

### Create a NSG (network security group ) and a NSG rule

The NSG secures our VM by using inbound and outbound rules.

Now, we need to create an inbound rule for port 3389 to allow incoming RDP (Remote Desktop) connections and an inbound rule for port 80 to let our VM receive the incoming web traffic.

#### Create an inbound NSG rule for the 3389 port
<pre><code class="language-powershell line-numbers">
# Create an inbound NSG rule for the 3389 port
# This rule will allow us to connect to the VM via an RDP connection
$nsgrdprule = New-AzureRmNetworkSecurityRuleConfig `
  -Name nsg-rdp-rule `
  -Protocol Tcp `
  -Direction Inbound `
  -Priority 1000 `
  -SourceAddressPrefix * `
  -SourcePortRange * `
  -DestinationAddressPrefix * `
  -DestinationPortRange 3389 `
  -Access Allow
</code></pre>

#### Create an inbound network security group rule for port 80
<pre><code class="language-powershell line-numbers">
# This rule will allow the VM to receive incoming web connections via the port 80
$nsgwebrule = New-AzureRmNetworkSecurityRuleConfig `
  -Name nsg-inbound-www-rule `
  -Protocol Tcp `
  -Direction Inbound `
  -Priority 1001 `
  -SourceAddressPrefix * `
  -SourcePortRange * `
  -DestinationAddressPrefix * `
  -DestinationPortRange 80 `
  -Access Allow
</code></pre>

#### Create the NSG (network security group)
<pre><code class="language-powershell line-numbers">
# This will wrap up previously created rules (nsg-web-rule and nsg-rdp-rule) within an NSG
$nsg = New-AzureRmNetworkSecurityGroup `
  -ResourceGroupName $ResourceGroupName `
  -Location $location `
  -Name nsg-1 `
  -SecurityRules $nsgrdprule,$nsgwebrule 

# This command will create a VNC (virtual network card) and associate it with public IP address and NSG
$nic = New-AzureRmNetworkInterface `
  -Name nic-1 `
  -ResourceGroupName $ResourceGroupName `
  -Location $location `
  -SubnetId $vnet.Subnets[0].Id `
  -PublicIpAddressId $publicip.Id `
  -NetworkSecurityGroupId $nsg.Id

# Define a credential object to store the username and password for the VM
$UserName='ali.mselmi'
$Password='P@ssword123'| ConvertTo-SecureString -Force -AsPlainText
$Credential=New-Object PSCredential($UserName,$Password)
</code></pre>

### Create the VM configuration object
<pre><code class="language-powershell line-numbers">
$VmName = "VirtualMachinelatest"
$VmSize = "Standard_A1"
$VirtualMachine = New-AzureRmVMConfig `
  -VMName $VmName `
  -VMSize $VmSize

$VirtualMachine = Set-AzureRmVMOperatingSystem `
  -VM $VirtualMachine `
  -Windows `
  -ComputerName "MainComputer" `
  -Credential $Credential -ProvisionVMAgent

$VirtualMachine = Set-AzureRmVMSourceImage `
  -VM $VirtualMachine `
  -PublisherName "MicrosoftWindowsServer" `
  -Offer "WindowsServer" `
  -Skus "2016-Datacenter" `
  -Version "latest"

# Sets the operating system disk properties on a VM.
$VirtualMachine = Set-AzureRmVMOSDisk `
  -VM $VirtualMachine `
  -CreateOption FromImage | `
  Set-AzureRmVMBootDiagnostics -ResourceGroupName $ResourceGroupName `
  -StorageAccountName $StorageAccountName -Enable |`
  Add-AzureRmVMNetworkInterface -Id $nic.Id
</code></pre>

### Create the VM

Finnaly we can create the VM deployment configuration.

<pre><code class="language-powershell line-numbers">

# Create the VM.
New-AzureRmVM `
  -ResourceGroupName $ResourceGroupName `
  -Location $location `
  -VM $VirtualMachine
</code></pre>

We can check the VM creation via the Azure portal:
<img src="https://mselmi.net/wp-content/uploads/2020/06/az-vm.png" alt="" />

### Connect to the VM

To do a remote access into the VM that we created in the previous step, we need its public IP address also previously set up.

To do that, we just need to run the following command and get the public IP address:

<pre><code class="language-powershell line-numbers">
Get-AzureRmPublicIpAddress `
  -ResourceGroupName $ResourceGroupName | Select IpAddress
</code></pre>

<img src="https://mselmi.net/wp-content/uploads/2020/06/az_vm_step_12-1.png" alt="" />

Now, we can do a remote desktop access after creating a Remote Desktop session with the VM, just you need replace the IP address with the publicIPAddress of your VM.
When prompted, you can login by using your credentials used when creating the VM.

<pre><code class="language-powershell line-numbers">
mstsc /v publicIpAddress
</code></pre>

<img src="https://mselmi.net/wp-content/uploads/2020/06/az_vm_step_13.png" alt="" />

# Connect to the Azure VM with an RDP, SSH or Bastion

You can connect to the VM via RDP, SSH or Bastion, you just need to click to the created VM via Azure portal and then click connect.
<img src="https://mselmi.net/wp-content/uploads/2020/06/azure-vm-rdp.png" alt="" />

### Delete the VM

We can use the following command to remove the resource group that contains the VM and its related resources:

<pre><code class="language-powershell line-numbers">
Remove-AzureRmResourceGroup `
  -Name $ResourceGroupName
</code></pre>

### Final words...

The advantage of scripting the entire VM creation process is that often we don't need to create a single VM, but to create several, creating a script for the process gives us the flexibility to customize the VMs creation at large-scale.