Troubleshooting Azure VM Connectivity Issues with PowerShell: A Practical Guide
As cloud engineers, one of the recurring headaches is when an Azure VM suddenly becomes unreachable. Maybe SSH or RDP just times out, and your immediate thought is: โWhat changed?โ Letโs walk through a real-world troubleshooting scenario and build a reusable PowerShell script to diagnose and fix common connectivity issues.
The Scenario
One of your critical Azure VMs is inaccessible. You canโt SSH into it, and attempts to ping it fail. You suspect network security group (NSG) rules, VM status, or routing issues.
Step 1: Check VM Status
First, letโs confirm the VM is running:
$resourceGroup = "ProdRG"
$vmName = "WebServer01"
$vm = Get-AzVM -ResourceGroupName $resourceGroup -Name $vmName -Status
if ($vm.Statuses.DisplayStatus -notmatch "VM running") {
Write-Warning "VM is not running. Current status: $($vm.Statuses.DisplayStatus)"
return
}
Write-Host "VM is running."
Step 2: Verify Network Interface and IP Configuration
Often, IP changes or NIC detachments cause issues:
$nicId = $vm.NetworkProfile.NetworkInterfaces[0].Id
$nic = Get-AzNetworkInterface -ResourceId $nicId
$ipConfig = $nic.IpConfigurations[0]
Write-Host "NIC Name: $($nic.Name)"
Write-Host "Private IP: $($ipConfig.PrivateIpAddress)"
Write-Host "Public IP ID: $($ipConfig.PublicIpAddress.Id)"
If thereโs a public IP, fetch it:
if ($ipConfig.PublicIpAddress) {
$publicIp = Get-AzPublicIpAddress -ResourceId $ipConfig.PublicIpAddress.Id
Write-Host "Public IP: $($publicIp.IpAddress)"
}
else {
Write-Host "No public IP assigned."
}
Step 3: Review NSG Rules
Misconfigured NSG rules often block inbound traffic. Letโs check the relevant NSG:
$nsgId = $nic.NetworkSecurityGroup.Id
$nsg = Get-AzNetworkSecurityGroup -ResourceId $nsgId
$allowedPorts = @(22, 3389) # SSH and RDP common ports
$rules = $nsg.SecurityRules | Where-Object {
$_.Access -eq "Allow" -and $_.Direction -eq "Inbound" -and $allowedPorts -contains $_.DestinationPortRange
}
if ($rules) {
Write-Host "Allowed inbound rules for SSH/RDP:"
$rules | Format-Table Name, Priority, SourceAddressPrefix, DestinationPortRange, Access
} else {
Write-Warning "No NSG allow rules found for SSH/RDP ports. Connectivity likely blocked."
}
Step 4: Test Connectivity From Azure
Use Azure Run Command to run a connectivity test from within the VM (requires VM agent):
$script = 'Test-NetConnection -ComputerName 8.8.8.8 -Port 53'
Invoke-AzVMRunCommand -ResourceGroupName $resourceGroup -Name $vmName -CommandId 'RunPowerShellScript' -ScriptString $script
This tests if the VM has outbound connectivity (e.g., DNS).
Step 5: Automating the Diagnosis
Combining all steps, hereโs a function that outputs the full diagnostic report:
function Test-AzureVmConnectivity {
param (
[Parameter(Mandatory)]
[string]$ResourceGroupName,
[Parameter(Mandatory)]
[string]$VmName
)
Write-Host "Checking VM status..."
$vm = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VmName -Status
if ($vm.Statuses.DisplayStatus -notmatch "VM running") {
Write-Warning "VM not running: $($vm.Statuses.DisplayStatus)"
return
}
Write-Host "VM is running."
$nicId = $vm.NetworkProfile.NetworkInterfaces[0].Id
$nic = Get-AzNetworkInterface -ResourceId $nicId
$ipConfig = $nic.IpConfigurations[0]
Write-Host "NIC Name: $($nic.Name)"
Write-Host "Private IP: $($ipConfig.PrivateIpAddress)"
if ($ipConfig.PublicIpAddress) {
$publicIp = Get-AzPublicIpAddress -ResourceId $ipConfig.PublicIpAddress.Id
Write-Host "Public IP: $($publicIp.IpAddress)"
} else {
Write-Host "No public IP assigned."
}
$nsgId = $nic.NetworkSecurityGroup.Id
$nsg = Get-AzNetworkSecurityGroup -ResourceId $nsgId
$allowedPorts = @(22, 3389)
$rules = $nsg.SecurityRules | Where-Object {
$_.Access -eq "Allow" -and $_.Direction -eq "Inbound" -and $allowedPorts -contains $_.DestinationPortRange
}
if ($rules) {
Write-Host "Allowed inbound rules for SSH/RDP:"
$rules | Format-Table Name, Priority, SourceAddressPrefix, DestinationPortRange, Access
} else {
Write-Warning "No NSG allow rules found for SSH/RDP ports."
}
Write-Host "Testing outbound connectivity from VM..."
$script = 'Test-NetConnection -ComputerName 8.8.8.8 -Port 53'
$result = Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroupName -Name $VmName -CommandId 'RunPowerShellScript' -ScriptString $script
$output = $result.Value[0].Message
Write-Host $output
}
Step 6: Extending to Auto-Heal NSG Rules
If the NSG is missing critical rules, automate adding them:
function Ensure-NSGRule {
param (
[Parameter(Mandatory)]
[Microsoft.Azure.Commands.Network.Models.PSNetworkSecurityGroup]$Nsg,
[string]$RuleName,
[int]$Port
)
if (-not ($Nsg.SecurityRules | Where-Object { $_.Name -eq $RuleName })) {
$rule = New-AzNetworkSecurityRuleConfig -Name $RuleName `
-Description "Allow inbound port $Port" `
-Access Allow -Protocol Tcp -Direction Inbound `
-Priority 1000 -SourceAddressPrefix '*' `
-SourcePortRange '*' -DestinationAddressPrefix '*' `
-DestinationPortRange $Port
$Nsg.SecurityRules.Add($rule)
Write-Host "Adding NSG rule $RuleName for port $Port"
$Nsg | Set-AzNetworkSecurityGroup
} else {
Write-Host "NSG rule $RuleName already exists."
}
}
Invoke it like this after fetching the NSG:
Ensure-NSGRule -Nsg $nsg -RuleName "Allow-SSH" -Port 22
Ensure-NSGRule -Nsg $nsg -RuleName "Allow-RDP" -Port 3389
Wrapping Up
This approach quickly identifies common causes for VM connectivity issues and can be integrated into scheduled maintenance scripts or alert-driven automation workflows. The combination of PowerShell and Azure CLI capabilities makes troubleshooting and healing infrastructure more predictable and less manual.
Automating AWS EC2 Instance Inventory and Health Check Using PowerShell and AWS CLI
Managing fleets of EC2 instances across multiple regions can get complex fast. Letโs build a PowerShell script that inventories EC2 instances, checks their status, and outputs a report you can use to trigger alerts or remediation.
The Challenge
You want to:
- List all running EC2 instances in specified AWS regions
- Check instance health status and system status checks
- Output results as CSV for ops dashboards or email reports
Step 1: Setting Up AWS CLI in PowerShell
Make sure AWS CLI is installed and configured (aws configure).
You can invoke AWS CLI commands from PowerShell directly:
$region = "us-east-1"
$instancesJson = aws ec2 describe-instance-status --region $region --output json | ConvertFrom-Json
Step 2: Fetch Instances and Status
We want both instance metadata and status:
$instanceStatusJson = aws ec2 describe-instance-status --region $region --include-all-instances --output json | ConvertFrom-Json
$instanceIds = $instanceStatusJson.InstanceStatuses.InstanceId
$instancesJson = aws ec2 describe-instances --region $region --instance-ids $instanceIds -output json | ConvertFrom-Json
Step 3: Build a Report Object
Loop through instances and correlate status:
“`powershell
$report = foreach ($status in $instanceStatusJson.InstanceStatuses) {
$instanceId = $status.InstanceId
$instance = $instancesJson.Reservations.Instances | Where-Object { $_.InstanceId -eq $instanceId }
[PSCustomObject]@{
InstanceId = $instanceId
Name = ($instance.Tags | Where-Object { $_.Key -eq
Leave a Reply