🚀 Automation for Creating a VM in Azure via PowerShell 🖥️🔧

📌 Description

This script automates the process of creating an Azure Virtual Machine (VM), resource group, storage account, and more, using PowerShell. Choose between various options to customize your setup, and the script will take care of the rest!

 

🚀 Features

Create a resource group in Azure

Deploy a Virtual Machine with your preferred configuration

Set up storage accounts and associated resources

Choose between different VM configurations and sizes

Automate deployment with minimal manual intervention

 

🛠️ Prerequisites

1- PowerShell installed

2- Azure PowerShell module installed

3- Azure subscription

PowerShell Script

  

  
  
# Check if the user is logged into Azure
if (-not (Get-AzContext)) {
    Write-Host "You must log in to Azure first!" -ForegroundColor Red
    Connect-AzAccount -TenantId "0711aea7-8f00-4e7f-aad3-3320c2bd8b9e"
}

# Function to display the menu with completed options highlighted
function Show-Menu {
    Clear-Host
    Write-Host "=== Azure VM Creator ===" -ForegroundColor Green
    if ($global:completedOptions["0"]) {
        Write-Host "0. Select region" -ForegroundColor Black -BackgroundColor Green
    } else {
        Write-Host "0. Select region" -ForegroundColor White
    }
    if ($global:completedOptions["1"]) {
        Write-Host "1. Specify resource group and VM name" -ForegroundColor Black -BackgroundColor Green
    } else {
        Write-Host "1. Specify resource group and VM name" -ForegroundColor White
    }
    if ($global:completedOptions["2"]) {
        Write-Host "2. Select Windows version and SKU" -ForegroundColor Black -BackgroundColor Green
    } else {
        Write-Host "2. Select Windows version and SKU" -ForegroundColor White
    }
    if ($global:completedOptions["3"]) {
        Write-Host "3. Specify CPU and RAM" -ForegroundColor Black -BackgroundColor Green
    } else {
        Write-Host "3. Specify CPU and RAM" -ForegroundColor White
    }
    if ($global:completedOptions["4"]) {
        Write-Host "4. Specify VM SKU" -ForegroundColor Black -BackgroundColor Green
    } else {
        Write-Host "4. Specify VM SKU" -ForegroundColor White
    }
    if ($global:completedOptions["5"]) {
        Write-Host "5. Select VM size" -ForegroundColor Black -BackgroundColor Green
    } else {
        Write-Host "5. Select VM size" -ForegroundColor White
    }
    if ($global:completedOptions["6"]) {
        Write-Host "6. Select disk type" -ForegroundColor Black -BackgroundColor Green
    } else {
        Write-Host "6. Select disk type" -ForegroundColor White
    }
    if ($global:completedOptions["7"]) {
        Write-Host "7. Show summary and create VM" -ForegroundColor Black -BackgroundColor Green
    } else {
        Write-Host "7. Show summary and create VM" -ForegroundColor White
    }
    Write-Host "8. Exit" -ForegroundColor White
    Write-Host "====================" -ForegroundColor Green
}

# Initial variables
$resourceGroupName = $null
$vmName = $null
$windowsVersion = $null
$selectedSku = $null
$cpuCores = $null
$ramGB = $null
$vmVariant = $null
$selectedSize = $null
$diskType = $null
$filteredSizes = $null
$location = $null # No default region, user must select
$global:completedOptions = @{} # Hash table to track completed options

# Main loop
while ($true) {
    Show-Menu
    $choice = Read-Host "Select an option (0-8)"
    Write-Host "You selected: '$choice'" -ForegroundColor Yellow # Debugging

    switch ($choice) {
        "0" {
            Write-Host "Running option 0" -ForegroundColor Yellow
            Write-Host "`nAvailable Azure regions:" -ForegroundColor Cyan
            $locations = Get-AzLocation | Sort-Object Location | Select-Object -Property Location
            $index = 1
            $locationList = @()
            $locations | ForEach-Object {
                Write-Host "$index. $($_.Location)"
                $locationList += $_.Location
                $index++
            }
            $locationChoice = Read-Host "Enter the number for the region you want to use (1-$($locationList.Count))"
            if (-not [int]::TryParse($locationChoice, [ref]$null)) {
                Write-Host "Invalid choice. Enter a number between 1 and $($locationList.Count)." -ForegroundColor Red
            } else {
                $locationChoiceInt = [int]$locationChoice
                if ($locationChoiceInt -lt 1 -or $locationChoiceInt -gt $locationList.Count) {
                    Write-Host "Invalid choice. Enter a number between 1 and $($locationList.Count)." -ForegroundColor Red
                } else {
                    $location = $locationList[$locationChoiceInt - 1]
                    Write-Host "Region set to: $location" -ForegroundColor Green
                    $global:completedOptions["0"] = $true
                }
            }
            Write-Host "Press Enter to continue..." -ForegroundColor Cyan
            Read-Host
        }
        "1" {
            Write-Host "Running option 1" -ForegroundColor Yellow
            if (-not $location) {
                Write-Host "Select a region first (option 0)." -ForegroundColor Red
            } else {
                $resourceGroupName = Read-Host "Enter the name of an existing resource group or a new one to create"
                $vmName = Read-Host "What should your Windows VM be called?"
                $rgExists = Get-AzResourceGroup -Name $resourceGroupName -ErrorAction SilentlyContinue
                if (-not $rgExists) {
                    Write-Host "Resource group '$resourceGroupName' does not exist. Creating a new one in ${location}..." -ForegroundColor Yellow
                    New-AzResourceGroup -Name $resourceGroupName -Location $location -Force | Out-Null
                    Write-Host "Resource group '$resourceGroupName' has been created." -ForegroundColor Green
                } else {
                    Write-Host "Resource group '$resourceGroupName' found in region $($rgExists.Location)." -ForegroundColor Yellow
                }
                if ($resourceGroupName -and $vmName) {
                    $global:completedOptions["1"] = $true
                }
            }
            Write-Host "Press Enter to continue..." -ForegroundColor Cyan
            Read-Host
        }
        "2" {
            Write-Host "Running option 2" -ForegroundColor Yellow
            if (-not $location) {
                Write-Host "Select a region first (option 0)." -ForegroundColor Red
            } else {
                Write-Host "`nFetching available Windows versions from Microsoft in region ${location}..." -ForegroundColor Cyan
                
                # List of approved Windows versions
                $approvedOffers = @("Windows-10", "Windows-11", "WindowsServer")
                
                # Fetch from MicrosoftWindowsDesktop
                $pubNameDesktop = "MicrosoftWindowsDesktop"
                $offersDesktop = Get-AzVMImageOffer -Location $location -PublisherName $pubNameDesktop | 
                                 Where-Object { $approvedOffers -contains $_.Offer } | 
                                 Select-Object -Property Offer
                
                # Fetch from MicrosoftWindowsServer
                $pubNameServer = "MicrosoftWindowsServer"
                $offersServer = Get-AzVMImageOffer -Location $location -PublisherName $pubNameServer | 
                                Where-Object { $_.Offer -eq "WindowsServer" } | 
                                Select-Object -Property Offer
                
                # Combine results
                $offers = $offersDesktop + $offersServer
                if (-not $offers) {
                    Write-Host "No approved Windows versions found in region ${location}." -ForegroundColor Red
                    Write-Host "Press Enter to continue..." -ForegroundColor Cyan
                    Read-Host
                    continue
                }
                
                $index = 1
                $offerList = @()
                $pubList = @() # To keep track of publisher for each offer
                $offers | ForEach-Object {
                    Write-Host "$index. $($_.Offer)"
                    $offerList += $_.Offer
                    if ($_.Offer -eq "WindowsServer") {
                        $pubList += $pubNameServer
                    } else {
                        $pubList += $pubNameDesktop
                    }
                    $index++
                }
                
                $offerChoice = Read-Host "Enter the number for the Windows version you want to use (1-$($offerList.Count))"
                $offerChoiceInt = [int]$offerChoice
                if ($offerChoiceInt -lt 1 -or $offerChoiceInt -gt $offerList.Count) {
                    Write-Host "Invalid choice. Enter a number between 1 and $($offerList.Count)." -ForegroundColor Red
                    Write-Host "Press Enter to continue..." -ForegroundColor Cyan
                    Read-Host
                    continue
                }
                $offerName = $offerList[$offerChoiceInt - 1]
                $pubName = $pubList[$offerChoiceInt - 1]

                Write-Host "`nAvailable SKUs for $offerName from ${pubName}:" -ForegroundColor Cyan
                $availableSkus = Get-AzVMImageSku -Location $location -PublisherName $pubName -Offer $offerName | Select-Object -Property Skus
                if (-not $availableSkus) {
                    Write-Host "No SKUs found for $offerName in region ${location}." -ForegroundColor Red
                    Write-Host "Press Enter to continue..." -ForegroundColor Cyan
                    Read-Host
                    continue
                }
                $index = 1
                $skuList = @()
                $availableSkus | ForEach-Object {
                    Write-Host "$index. $($_.Skus)"
                    $skuList += $_.Skus
                    $index++
                }
                $skuChoice = Read-Host "Enter the number for the SKU you want to use (1-$($skuList.Count))"
                $skuChoiceInt = [int]$skuChoice
                if ($skuChoiceInt -lt 1 -or $skuChoiceInt -gt $skuList.Count) {
                    Write-Host "Invalid choice. Enter a number between 1 and $($skuList.Count)." -ForegroundColor Red
                } else {
                    $selectedSku = $skuList[$skuChoiceInt - 1]
                    $windowsVersion = $offerName
                    Write-Host "Selected version: $windowsVersion, SKU: $selectedSku from $pubName" -ForegroundColor Green
                    $global:completedOptions["2"] = $true
                }
            }
            Write-Host "Press Enter to continue..." -ForegroundColor Cyan
            Read-Host
        }
        "3" {
            Write-Host "Running option 3" -ForegroundColor Yellow
            $cpuCores = Read-Host "Enter the number of CPU cores (e.g., 2)"
            $ramGB = Read-Host "Enter the RAM size in GB (e.g., 4)"
            if (-not [int]::TryParse($cpuCores, [ref]$null) -or -not [int]::TryParse($ramGB, [ref]$null)) {
                Write-Host "CPU and RAM must be numeric values. Try again." -ForegroundColor Red
            } else {
                Write-Host "CPU set to: $cpuCores, RAM set to: $ramGB GiB" -ForegroundColor Green
                $global:completedOptions["3"] = $true
            }
            Write-Host "Press Enter to continue..." -ForegroundColor Cyan
            Read-Host
        }
        "4" {
            Write-Host "Running option 4" -ForegroundColor Yellow
            $vmVariant = Read-Host "Enter VM SKU (Standard)"
            if ($vmVariant -ne "Standard") {
                Write-Host "Invalid VM SKU. Only 'Standard' is allowed. Try again." -ForegroundColor Red
            } else {
                Write-Host "VM SKU set to: $vmVariant" -ForegroundColor Green
                $global:completedOptions["4"] = $true
            }
            Write-Host "Press Enter to continue..." -ForegroundColor Cyan
            Read-Host
        }
        "5" {
            Write-Host "Running option 5" -ForegroundColor Yellow
            if (-not $location) {
                Write-Host "Select a region first (option 0)." -ForegroundColor Red
            } elseif (-not $cpuCores -or -not $ramGB -or -not $vmVariant -or -not $windowsVersion -or -not $selectedSku) {
                Write-Host "Specify Windows version, SKU, CPU, RAM, and VM SKU first (options 2, 3, and 4)." -ForegroundColor Red
            } else {
                Write-Host "# Warning: Previous errors may have occurred if you selected an ARM64-based VM size (e.g., Standard_D4pls_v5) with an x64 image. This script uses x64 images (Windows 10, 11, Server) and now lists only x64-compatible sizes." -ForegroundColor Yellow
                
                # Fetch available sizes, excluding ARM64
                $availableSizes = Get-AzVMSize -Location $location | Where-Object { 
                    $_.Name -like "Standard*" -and 
                    $_.Name -notlike "*pl*" # Exclude ARM64-based sizes like Dplsv5
                }
                $sizeReference = $availableSizes | ForEach-Object {
                    [PSCustomObject]@{
                        Name = $_.Name
                        CPU = $_.NumberOfCores
                        RAM_GB = [math]::Round($_.MemoryInMB / 1024, 2)
                    }
                }

                Write-Host "Total number of available sizes in ${location}: $($sizeReference.Count)" -ForegroundColor Yellow

                # Filter sizes based on Gen1 or Gen2
                if ($windowsVersion -eq "Windows-11" -or $selectedSku -match "gen2" -or $selectedSku -match "22h2") {
                    $filteredSizes = $sizeReference | Where-Object {
                        $_.CPU -eq $cpuCores -and $_.RAM_GB -eq $ramGB -and $_.Name -match "Standard_D.*s_v[2-5]"
                    } | Sort-Object -Property Name
                    Write-Host "Note: Selected SKU requires a Gen2-compatible size (e.g., Standard_D2s_v3)." -ForegroundColor Yellow
                } else {
                    $filteredSizes = $sizeReference | Where-Object {
                        $_.CPU -eq $cpuCores -and $_.RAM_GB -eq $ramGB -and $_.Name -match "Standard_A[1-4]_v2"
                    } | Sort-Object -Property Name
                }

                Write-Host "Number of filtered sizes: $($filteredSizes.Count)" -ForegroundColor Yellow
                if ($filteredSizes) {
                    Write-Host "Filtered sizes (raw data):" -ForegroundColor Yellow
                    $filteredSizes | ForEach-Object { Write-Host "- $($_.Name)" -ForegroundColor Yellow }
                } else {
                    Write-Host "No filtered sizes found." -ForegroundColor Yellow
                }

                if (-not $filteredSizes -or $filteredSizes.Count -eq 0) {
                    Write-Host "No VM size found for $cpuCores vCPU and $ramGB GiB RAM in ${vmVariant}. Choose different values." -ForegroundColor Red
                } else {
                    Write-Host "`nAvailable VM sizes in ${location}:" -ForegroundColor Cyan
                    $index = 1
                    $sizeList = @()
                    $filteredSizes | ForEach-Object {
                        Write-Host "$index. $($_.Name) - $($_.CPU) vCPUs, $($_.RAM_GB) GiB RAM"
                        $sizeList += $_
                        $index++
                    }
                    
                    Write-Host "Number of items in sizeList: $($sizeList.Count)" -ForegroundColor Yellow
                    
                    $sizeChoice = Read-Host "Enter the number for the VM size you want to use (1-$($sizeList.Count))"
                    if (-not [int]::TryParse($sizeChoice, [ref]$null)) {
                        Write-Host "Invalid choice. Enter a number between 1 and $($sizeList.Count)." -ForegroundColor Red
                    } else {
                        $sizeChoiceInt = [int]$sizeChoice
                        Write-Host "Selected number: $sizeChoiceInt" -ForegroundColor Yellow
                        if ($sizeChoiceInt -lt 1 -or $sizeChoiceInt -gt $sizeList.Count) {
                            Write-Host "Invalid choice. Enter a number between 1 and $($sizeList.Count)." -ForegroundColor Red
                        } else {
                            $selectedSize = $sizeList[$sizeChoiceInt - 1].Name
                            Write-Host "VM size set to: $selectedSize" -ForegroundColor Green
                            $global:completedOptions["5"] = $true
                        }
                    }
                }
            }
            Write-Host "Press Enter to continue..." -ForegroundColor Cyan
            Read-Host
        }
        "6" {
            Write-Host "Running option 6" -ForegroundColor Yellow
            Write-Host "`nSelect a disk type for the OS disk:" -ForegroundColor Cyan
            Write-Host "1. Premium SSD (High performance)"
            Write-Host "2. Standard SSD (Balanced cost and performance)"
            Write-Host "3. Standard HDD (Low cost)"
            $diskChoice = Read-Host "Enter the number for the disk type (1-3)"
            switch ($diskChoice) {
                "1" { $diskType = "Premium_LRS"; Write-Host "Disk type set to: Premium SSD" -ForegroundColor Green; $global:completedOptions["6"] = $true }
                "2" { $diskType = "StandardSSD_LRS"; Write-Host "Disk type set to: Standard SSD" -ForegroundColor Green; $global:completedOptions["6"] = $true }
                "3" { $diskType = "Standard_LRS"; Write-Host "Disk type set to: Standard HDD" -ForegroundColor Green; $global:completedOptions["6"] = $true }
                default { Write-Host "Invalid disk type. Try again." -ForegroundColor Red }
            }
            Write-Host "Press Enter to continue..." -ForegroundColor Cyan
            Read-Host
        }
        "7" {
            Write-Host "Running option 7" -ForegroundColor Yellow
            if (-not $location -or -not $resourceGroupName -or -not $vmName -or -not $windowsVersion -or -not $selectedSku -or -not $cpuCores -or -not $ramGB -or -not $vmVariant -or -not $selectedSize -or -not $diskType) {
                Write-Host "All options must be specified first. Use options 0-6 to fill in the information." -ForegroundColor Red
            } else {
                Write-Host "Summary:" -ForegroundColor Cyan
                Write-Host "Region: $location"
                Write-Host "Resource group: $resourceGroupName"
                Write-Host "VM name: $vmName"
                Write-Host "Windows version: $windowsVersion (SKU: $selectedSku)"
                Write-Host "CPU: $cpuCores vCPUs"
                Write-Host "RAM: $ramGB GiB"
                Write-Host "VM size: $selectedSize"
                Write-Host "Disk type: $diskType"
                
                $createVM = Read-Host "Do you want to create the VM? (y/n)"
                if ($createVM -eq "y") {
                    Write-Host "Creating VM..." -ForegroundColor Green
                    
                    $adminUser = Read-Host "Enter the administrator username for the VM"
                    $adminPassword = Read-Host "Enter the administrator password" -AsSecureString
                    $credential = New-Object System.Management.Automation.PSCredential ($adminUser, $adminPassword)

                    $publisher = if ($windowsVersion -eq "WindowsServer") { "MicrosoftWindowsServer" } else { "MicrosoftWindowsDesktop" }
                    $offer = $windowsVersion
                    if ($windowsVersion -eq "Windows-11") {
                        Write-Host "Warning: Windows 11 requires a Gen2-compatible VM size (e.g., Standard_D2s_v3)." -ForegroundColor Yellow
                    }

                    $vnetName = "$vmName-vnet"
                    $subnetName = "$vmName-subnet"
                    $vnet = Get-AzVirtualNetwork -Name $vnetName -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue
                    if (-not $vnet) {
                        $subnetConfig = New-AzVirtualNetworkSubnetConfig -Name $subnetName -AddressPrefix "10.0.0.0/24"
                        $vnet = New-AzVirtualNetwork -ResourceGroupName $resourceGroupName -Location $location -Name $vnetName -AddressPrefix "10.0.0.0/16" -Subnet $subnetConfig
                    }
                    $subnet = Get-AzVirtualNetworkSubnetConfig -Name $subnetName -VirtualNetwork $vnet

                    $publicIpName = "$vmName-ip"
                    $publicIp = New-AzPublicIpAddress -ResourceGroupName $resourceGroupName -Location $location -Name $publicIpName -AllocationMethod Static -Sku Standard

                    $nicName = "$vmName-nic"
                    $nsgName = "$vmName-nsg"
                    $nsgRuleName = "AllowRDP"
                    
                    # Create NSG and rule for RDP
                    $nsgRule = New-AzNetworkSecurityRuleConfig -Name $nsgRuleName -Protocol Tcp -Direction Inbound -Priority 100 -SourceAddressPrefix * -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 3389 -Access Allow
                    $nsg = New-AzNetworkSecurityGroup -ResourceGroupName $resourceGroupName -Location $location -Name $nsgName -SecurityRules $nsgRule

                    $nic = New-AzNetworkInterface -ResourceGroupName $resourceGroupName -Location $location -Name $nicName -SubnetId $subnet.Id -PublicIpAddressId $publicIp.Id -NetworkSecurityGroupId $nsg.Id

                    $vmConfig = New-AzVMConfig -VMName $vmName -VMSize $selectedSize |
                                Set-AzVMOperatingSystem -Windows -ComputerName $vmName -Credential $credential |
                                Set-AzVMSourceImage -PublisherName $publisher -Offer $offer -Skus $selectedSku -Version "latest" |
                                Add-AzVMNetworkInterface -Id $nic.Id |
                                Set-AzVMOSDisk -StorageAccountType $diskType -CreateOption FromImage

                    try {
                        New-AzVM -ResourceGroupName $resourceGroupName -Location $location -VM $vmConfig -ErrorAction Stop
                        Write-Host "VM '$vmName' has been created successfully!" -ForegroundColor Green
                        $global:completedOptions["7"] = $true
                    } catch {
                        Write-Host "Error creating VM: $_" -ForegroundColor Red
                    }
                } else {
                    Write-Host "VM creation canceled." -ForegroundColor Yellow
                }
            }
            Write-Host "Press Enter to continue..." -ForegroundColor Cyan
            Read-Host
        }
        "8" {
            exit
        }
        default {
            Write-Host "Invalid choice registered: '$choice'" -ForegroundColor Red
        }
    }
}
  

Kommentarer

Populära inlägg i den här bloggen

🚀 IntuneWin – Deploying Win32 Apps via Intune 🎯

Boost Your Graphics Power med GPU-acceleration i Azure Virtual Desktop!

Block Personal devices to acces to Desktop apps like teams, Onedrive etc and how to troubleshooting the issue.