One of the areas that you need to study and learn for the AZ-104 is deploying and managing computer resources. Of course, one of them is all about virtual machines. I worked on projects and wrote about it on my GitHub page. I have added it here so you all can have it here as well. =)

Creating a VM

I have already created a VM several times through the portal. I’ve also found an Azure Quickstart Template Gallery. I went and deployed a simple VM.

How about in PowerShell?

I started off in ChatGPT that the script was probably 40% accurate. After that, I went to the Microsoft pages on Powershell script for the different resources I was creating. FINALLY, after tweaking here and there, I got the VM created with the other resources like the VNET, Network Security Group, and Network Interface. Here is the code:

Connect-AzAccount


Set-AzContext -SubscriptionId "224b21e7-ab59-4f9d-bfa3-a0c6261321ad"


$resourceGroup = “vmLearnResourceGroup"

$location = "EastUS"


New-AzResourceGroup -Name $resourceGroup -Location $location


$vnet = New-AzVirtualNetwork -ResourceGroupName $resourceGroup -Location $location -Name "myVnet" -AddressPrefix "10.0.0.0/16"


$subnet = Add-AzVirtualNetworkSubnetConfig -Name "mySubnet" -AddressPrefix "10.0.0.0/24" -VirtualNetwork $vnet

$vnet | Set-AzVirtualNetwork


$nsg = Get-AzNetworkSecurityGroup -Name "myNSG" -ResourceGroupName $resourceGroup


$nsg | Add-AzNetworkSecurityRuleConfig -Name allowAppPort$port -Description "Allow app port" -Access Allow -Protocol  -Direction Inbound -Priority 1000 -SourceAddressPrefix "" -SourcePortRange  -DestinationAddressPrefix  -DestinationPortRange 3389


$nsg | Set-AzNetworkSecurityGroup


$ip = @{

 Name = 'myPublicIP'

 Sku = 'Standard'

 AllocationMethod = 'Static'

 IpAddressVersion = 'IPv4'

 Zone = 1,2,3

}


$IP1 = @{

 Name = 'ipconfig1'

 Subnet = $vnet.Subnets[0]

 PrivateIpAddressVersion = 'IPv4'

 PublicIPAddress = $pubIP

}

$IP1Config = New-AzNetworkInterfaceIpConfig @IP1 -Primary


$nic = @{

 Name = 'myNIC'

 ResourceGroupName = $resourceGroup

 Location = $location

 IpConfiguration = $IP1Config

}

New-AzNetworkInterface @nic$cred = Get-Credential


New-AzVm -ResourceGroupName $resourceGroup -Name 'devVM4Learn' -Location $location -Image 'MicrosoftWindowsServer:WindowsServer:2022-datacenter-azure-edition:latest' -VirtualNetworkName $vnet -SubnetName $subnet -SecurityGroupName $nsg -PublicIpAddressName $ip -OpenPorts 80,3389

The good thing is that now I have a script to create:

  • Resource Group
  • Virtual Network
  • Subnet
  • Network Security Group
  • Network Security Group Rule
  • Network Interface
  • Virtual Machine

Creating VMs using Powershell and Bicep

Whenever you have trouble deciding what projects to help you gain Azure experience, Microsoft offers exceptional labs and demos that you can use. For learning about virtual machines, I used the one that I am linking here. Additionally, I decided to create a virtual machine image that wasn’t available in the labs, but I saw on a Udemy course that I am taking.

As a result, I updated the PowerShell code I initially wrote. One thing to know is that you can always improve upon your code. I made a few updates, particularly to the Network Security group. I optimized the code to ensure its ease of use without any warnings or errors during compilation. Below is the code detailing the virtual machine PowerShell changes I made:

#Used to login to Azure 
Connect-AzAccount

#Select the Azure subscription that you want to work on 
Set-AzContext -SubscriptionId "224b21e7-ab59-4f9d-bfa3-a0c6261321ad"

#Variables that you will use later in your code.  Good practice so you dont have to keep entering the actual names over and over again
$resourceGroup = “vmLearnResourceGroup"

$location = "EastUS"

#Cmdlet to create a new resource group 
New-AzResourceGroup -Name $resourceGroup -Location $location

#Virtual network and subnet creation 
$vnet = New-AzVirtualNetwork -ResourceGroupName $resourceGroup -Location $location -Name "myVnet" -AddressPrefix "10.0.0.0/16"

$subnet = Add-AzVirtualNetworkSubnetConfig -Name "mySubnet" -AddressPrefix "10.0.0.0/24" -VirtualNetwork $vnet

$vnet | Set-AzVirtualNetwork

#Instead of using Get, I changed it to New and this resolved some of the warnings I got before 
$nsg = New-AzNetworkSecurityGroup -Name "myNSG" -ResourceGroupName $resourceGroup

# Add a new Network Security Rule to the NSG
$rule = New-AzNetworkSecurityRuleConfig -Name "rdp-rule" -Description "Allow RDP" -Access "Allow" -Protocol "Tcp" -Direction           "Inbound" -Priority 100 -SourceAddressPrefix "Internet" -SourcePortRange "*" -DestinationAddressPrefix "*" -DestinationPortRange 3389


$nsg.SecurityRules.Add($rule)

$nsg | Set-AzNetworkSecurityGroup

#Create a public IP
$ip = @{

 Name = 'myPublicIP'

 Sku = 'Standard'

 AllocationMethod = 'Static'

 IpAddressVersion = 'IPv4'

 Zone = 1,2,3

}


$IP1 = @{

 Name = 'ipconfig1'

 Subnet = $vnet.Subnets[0]

 PrivateIpAddressVersion = 'IPv4'

 PublicIPAddress = $pubIP

}

  $IP1Config = New-AzNetworkInterfaceIpConfig @IP1 -Primary

  #Create a network interface card 

  $nic = @{

   Name = 'myNIC'

   ResourceGroupName = $resourceGroup

   Location = $location

     IpConfiguration = $IP1Config

    }

New-AzNetworkInterface @nic$cred = Get-Credential

#Now the pieces fall into place to create the VM
New-AzVm -ResourceGroupName $resourceGroup -Name 'devVM4Learn' -Location $location -Image         'MicrosoftWindowsServer:WindowsServer:2022-datacenter-azure-edition:latest' -VirtualNetworkName $vnet -SubnetName $subnet -    SecurityGroupName $nsg -PublicIpAddressName $ip -OpenPorts 80,3389

You’re probably going to take a 2-4 of days to work on this project especially if you have other commitments like work, school, kids, hobbies, etc. Therefore, make sure that you STOP YOUR VM(s). I learned that the hard way. You do not want to log on and have a huge cost to pay.

With Azure’s bicep, you can push Infrastructure as Code (IaC), so it’s good to know how to use it. It’s more user-friendly than Powershell, but you still need to use CLI or PowerShell to actually deploy the files, just like with ARM Templates.

Microsoft gets you started with a template that’s already ready to go. I got stuck on the fact that even though visual studio code shows that I installed the Bicep extension, I didn’t actually install Bicep. It took me searching for this error to figure it out:

    New-AzResourceGroupDeployment: Cannot retrieve the dynamic parameters for the cmdlet

I then installed Bicep. Eventually I got past this error, but the deployment still didn’t work. Based on what I read about the bicep syntax, and what I saw in ChatGPT, I hadn’t defined the username and password. I made sure to do that, and it worked! Besides the VNet, SubNet, etc, it also deployed the other resources.

Though I still need to learn Powershell and CLI, I like bicep.

Creating VM Image

Creating a VM image wasn’t as straightforward as Microsoft says, and I think what bugs me is that they have code that you think “Yay, I can just copy and paste.” NOOOOO, it is never 100% correct. The CLI Help was a great resource to fix some of the code that Microsoft had.

Decided why not use CLI this time.

# Created VM before I did this I did use the "az group create" to create the resource group.  I then used this to create a VM.  It also created a VNET, NIC, etc. 
az vm create --name FLtoVAVM --resource-group FLtoVAResourceGroup --image Win2022AzureEditionCore --generate-ssh-keys

# I then created an image gallery 
az sig create --resource-group FLtoVAResourceGroup --gallery-name WinVMGallery 

An example of what I was talkin about. This is what Microsoft said to use (of course I changed the variables) for the image definition:

az sig image-definition create \
   --resource-group FLtoVAResourceGroup \
   --gallery-name WinVMGallery \
   --gallery-image-definition myWinmageDefinition \
  --publisher GreatPublisher \
 --offer GreatOffer \
—sku GreatSku \
   --os-type Windows \
   --os-state specialized

But when I plugged it in, it didn’t work. CLI gave me suggestions, and this did work:

az sig image-definition create --resource-group FLtoVAResourceGroup --gallery-name WinVMGallery --gallery-image-definition MyImage 
    --publisher GreatPublisher --offer GreatOffer --sku GreatSku --os-type Windows

I then used the CLI recommended by the Intellisense to create a VM version:

az sig image-version create --resource-group FLtoVAResourceGroup --gallery-name WinVMGallery --gallery-image-definition         myImageDefinition --gallery-image-version 1.0.0 --target-regions “eastus" “eastus2” "eastus=1=standard_zrs" --replica-count 2 --managed-    image "/subscriptions/224b21e7-ab59-4f9d-bfa3-    a0c6261321ad/resourceGroups/FLtoVAResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM"

On the projects I’ve been on, you usually use an image from the marketplace, so you would use the portal or a Powershell script like the one below (Note: You might have to do some tweaking of the code):

    # Set the Marketplace image
    $offerName = "windows-data-science-vm"
    $skuName = "windows2016"
    $version = "19.01.14"
    $vmConfig = Set-AzVMSourceImage -VM $vmConfig -PublisherName $publisherName -Offer $offerName -Skus $skuName -Version $version

    # Set the Marketplace plan information, if needed
    $publisherName = "microsoft-ads"
    $productName = "windows-data-science-vm"
    $planName = "windows2016"
    $vmConfig = Set-AzVMPlan -VM $vmConfig -Publisher $publisherName -Product $productName -Name $planName

After that, I deleted the entire resource group (so I wouldn’t pay crazy amounts of money), using the following CLI command:

    az group delete --name FLtoVAResourceGroup

Change VM Disk Size Type

A CSA at work asked someone to create a Powershell script to change the disk space of multiple VMs from Premium SSD to Standard. I decided to try to figure it out myself so I could learn while doing it. The first thing I did was create the different variables and add the components that I knew how to do like

Connect-AzAccount

Set the subscription

# Set your subscription ID
$subscriptionId = "110155ef-224c-44a0-8776-7efa3531e59b"

Update-AzConfig -DefaultSubscriptionForLogin $subscriptionId

And get virtual machines in a resource group

  Get-AzVM -ResourceGroupName "PremtoStd"

After that, I was stuck because I didn’t know which loop to use and how to do it in Powershell. This is when I used ChatGPT. It suggested the “foreach” loop. As always, I had to do my own research to tweak it. The first thing I found is that before you can change the disk type of a VM, you need to stop (or dellocate) all the VMs that are in scope. I looked on the Microsoft site and found out how to do it using:

  Stop-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Force

Foreach loop is used when you every item in your criteria to have something happen to them. Therefore, this one says, stop all VMS, and then for each data disk in the VMS, chnage the SKU from Premium to Standard.

I also found out how useful the WriteOutput command is because it will display on the screen a message that you choose. It’s good when you are trying to troubleshoot or make sure the right action is being performed.

Example is:

Write-Output "Changing disk SKU for VM: $($vm.Name), Disk: $($disk.Name)"

After the disk SKU is changed, it will restart the VMs.

Whole script:

# Connect to your Azure account
Connect-AzAccount

# Set your subscription ID
$subscriptionId = "110155ef-224c-44a0-8776-7efa3531e59b"

Set-AzContext -SubscriptionId $subscriptionId

# Variables for resource group and VM names
$resourceGroupName = "PremtoStd"

# Get all the VMs in the specified resource group
$vms = Get-AzVM -ResourceGroupName "$PremtoStd"

foreach ($vm in $vms) {
    # Deallocate the VM
    Write-Output "Deallocating VM: $($vm.Name)"
Stop-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Force

# Get the VM details
$vmDetails = Get-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name

# Loop through each data disk
foreach ($disk in $vmDetails.StorageProfile.DataDisks) {
        # Get the managed disk details
        $managedDisk = Get-AzDisk -ResourceGroupName $vm.ResourceGroupName -DiskName $disk.Name

        # Change the SKU from Premium_LRS to Standard_LRS
        if ($managedDisk.Sku.Name -eq 'Premium_LRS') {
            $managedDisk.Sku.Name = 'Standard_LRS'
            Write-Output "Changing disk SKU for VM: $($vm.Name), Disk: $($disk.Name)"

            # Update the managed disk with the new SKU
            Update-AzDisk -ResourceGroupName $vm.ResourceGroupName -DiskName $managedDisk.Name -Disk $managedDisk
            Write-Output "Updated disk: $($disk.Name) to Standard_LRS"
        }
      }

    # Loop through the OS disk
    $osDisk = $vmDetails.StorageProfile.OsDisk
    $osDiskDetails = Get-AzDisk -ResourceGroupName $vm.ResourceGroupName -DiskName $osDisk.Name

    if ($osDiskDetails.Sku.Name -eq 'Premium_LRS') {
        $osDiskDetails.Sku.Name = 'Standard_LRS'
        Write-Output "Changing OS disk SKU for VM: $($vm.Name)"

        # Update the OS disk with the new SKU
        Update-AzDisk -ResourceGroupName $vm.ResourceGroupName -DiskName $osDiskDetails.Name -Disk $osDiskDetails
        Write-Output "Updated OS disk to Standard_LRS"
    }

    # Start the VM
    Write-Output "Starting VM: $($vm.Name)"
    Start-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name
    Write-Output "VM: $($vm.Name) is now running with Standard SSD disks"

}

Recommended Posts

Skip to content