Create and assign a public ip to an Azure Virtual Machine using Azure PowerShell (Az).

Sometimes deliberately we don’t create and assign a public ip to an Azure Virtual Machine to not to expose to the internet as a safety measure, but later at some point of time we may require the VM to be accessed via internet and we definitely need a public ip to access the VM, the script below will help to create and assign a public ip address to an Azure VM…

Note: If no Network Security Group is associated with Virtual Machine, by default all ports are open to the internet, and please be careful.


#requires -Module Az

# Function to create and assign a public ip address 
# to an Azure Virtual Machine using Az PowerShell module.
Function Assign-AzVMPublicIP2
{
Param
(
# Resource Group Name
[Parameter(Mandatory=$true)]
[string] $ResourceGroupName,
# Virtual Machine Name
[Parameter(Mandatory=$true)]
[string] $VMName
)
# Retrieve the Virtual Machine details
$VM = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VMName -ErrorAction SilentlyContinue

# Checking the VM existance
if($null -eq $VM)
{
Write-Error "Please enter a valid and existing Resource Group Name and Virtual Machine Name"
return
}

$Location = $VM.Location # Location to create a public ip
$NICId = $VM.NetworkProfile.NetworkInterfaces.Id # Network Interface resource id
$NICResource = Get-AzResource -ResourceId $NICId # Retrieve the NIC resource details

# Retrive the NIC Object
$NIC = Get-AzNetworkInterface -Name $NICResource.Name -ResourceGroupName $NICResource.ResourceGroupName
$NICIPConfigName = $NIC.ipConfigurations[0].Name # IP Config Name to be used with Set-AzNetworkInterfaceIpConfig CmdLet
$NICSubnetId = $NIC.ipConfigurations[0].subnet.id # Subnet id to be used with Set-AzNetworkInterfaceIpConfig CmdLet

# Create a public ip
$PublicIP = New-AzPublicIpAddress -ResourceGroupName $ResourceGroupName -Location $Location -Name "$VMName-pip" -AllocationMethod Static -IdleTimeoutInMinutes 4

# Warn the user if no NSG is associated with this VM
if ($null -eq $NIC.NetworkSecurityGroup)
{
Write-Warning "Since no Network Security Group is associated with this Virtual Machine, by default all ports are open to the internet."
}

# Assign the public ip to the VM NIC
$NIC | Set-AzNetworkInterfaceIpConfig -Name $NICIPConfigName -SubnetId $NICSubnetId -PublicIpAddressId $PublicIP.Id | Set-AzNetworkInterface
}

Assign-AzVMPublicIP2 -ResourceGroupName test-rg -VMName test-vm

Retieve Azure VM public ip and establish the RDP session through PowerShell

I don’t know for some reason Microsoft doesn’t provide some solutions directly, directly as in cannot achieve the outcome with a single command in PowerShell, for example to get the public ip address of an Azure VM, in fact I expected it to be as simple as this…


Get-AzureRmPublicIpAddress -ResourceGroupName lab-rg -Name Workstation

However there is no such command with those parameters, but still it’s not very complicated. I have written a small PowerShell wrapper to retrieve the public ip address of Azure VM and added few more functionalities as well apart from getting only the public ip address it will start the VM if it is not running by enabling the ‘-StartIfVMIsNotRunning’ flag and connect to RDP session with ‘-ConnectRDP’ flag.

Note: Most of the organizations use either private ip or dns name to connect to the VM from their network, and this is only useful for small businesses or where there is no need of domain authentication and access from outside the local network.

The script has two parameter sets ‘Name’ and ‘Object’, which accepts ResourceGroupName and VMName or VMObject along with the other common parameters, and the parameters are as below…


[Parameter(Mandatory=$true,ParameterSetName='Name')]
[string] $ResourceGroupName, # ResourceGroup Name when the ParameterSetName is 'Name'
[Parameter(Mandatory=$true,ParameterSetName='Name')]
[string] $VMName, # Virtual Machine Name when the ParameterSetName is 'Name'
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName='Object')]
[Microsoft.Azure.Commands.Compute.Models.PSVirtualMachine]
$VMObject, # VM Object when the ParameterSetName is 'Object'
[Parameter(Mandatory=$false,ParameterSetName='Name')]
[Parameter(Mandatory=$false,ParameterSetName='Object')]
[switch] $StartIfVMIsNotRunning, # Start the VM, if it is not running
[Parameter(Mandatory=$false,ParameterSetName='Name')]
[Parameter(Mandatory=$false,ParameterSetName='Object')]
[switch] $ConnetRDP, # Connect Remote Desktop Session
[Parameter(Mandatory=$true,ParameterSetName='Help')]
[switch] $H # Get Help

Since the latest AzureRM (6.13.1) PowerShell module has some significant changes in the outcome of some CmdLets, ensuring the latest module is loaded…

# Ensure the 6.13.1 version AzureRM module is loaded,
# because some commands output have been changed in this version
[System.Version] $RequiredModuleVersion = '6.13.1'
[System.Version] $ModuleVersion = (Get-Module -Name AzureRM).Version
if ($ModuleVersion -lt $RequiredModuleVersion)
{
Write-Verbose -Message "Import latest AzureRM module"
break
}

Login into Azure account, if not logged in already…


# Login in into the Azure account, if it is not already logged in
if([string]::IsNullOrEmpty($(Get-AzureRmContext)))
{
$null = Add-AzureRmAccount
}

Retrieve the VM running state and ensure it is running, if ‘-StartIfVMIsNotRunning’ flag is enabled then the VM will be started if it is not running. If VM is not running and ‘PublicIPAllocationMethod’ is set to static then still public ip can be retrieved, but if it is dynamic then the VM should be in running state itself…


# Retrieve the virtual machine running status
try
{
if ($PSCmdlet.ParameterSetName -eq 'Name')
{
[Microsoft.Azure.Commands.Compute.Models.PSVirtualMachineInstanceView] $VM = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMName -Status
}
elseif ($PSCmdlet.ParameterSetName -eq 'Object')
{
[Microsoft.Azure.Commands.Compute.Models.PSVirtualMachineInstanceView] $VM = Get-AzureRmVM -ResourceGroupName $VMObject.ResourceGroupName -Name $VMObject.Name -Status
}
}
catch
{
Write-Verbose -Message $_.Exception.Message
break
}

# Check whether the vm PowerState is running
[Microsoft.Azure.Management.Compute.Models.InstanceViewStatus] $VMStatus = $VM.Statuses | Where-Object { $_.Code -match 'running' }
if ([string]::IsNullOrEmpty($VMStatus))
{
[bool] $ISVMRunning = $false } else { [bool] $ISVMRunning = $true
}

# If VM is not running and -StartIfVMIsNotRunning flag is enabled, then start the VM
if ($ISVMRunning -eq $false -and $StartIfVMIsNotRunning -eq $true)
{
$null = Start-AzureRMVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name
$ISVmRunning = $true
}

Now retrieve the public ip address of an Azure VM…


# Get Public IP address
[Microsoft.Azure.Commands.Compute.Models.PSVirtualMachine] $VirtualMachine = Get-AzureRMVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name
[string] $NICId = $VirtualMachine.NetworkProfile.NetworkInterfaces.id
[Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResource] $NICResource = Get-AzureRmResource -ResourceId $NICId
[string] $PIPId = $NICResource.Properties.ipConfigurations.properties.publicIPAddress.id
[Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResource] $PIPResource = Get-AzureRmResource -ResourceId $PIPId
[ipaddress] $PIP = $PIPResource.Properties.ipAddress

Exit the script if the VM is not running and PublicIPAllocationMethod is Dynamic or public ip is not assigned…


# Exit the script if the VM is not running and PublicIPAllocationMethod is Dynamic or public ip is not assigned
[string] $PublicIPAllocationMethod = $PIPResource.Properties.publicIPAllocationMethod
if ([string]::IsNullOrEmpty($PIP.IPAddressToString) -and $ISVMRunning -eq $false -and $PublicIPAllocationMethod -eq 'Dynamic')
{
Write-Verbose -Message $("Since {0} VM is not running and 'Public IP Allocation Method is Dynamic', unable to determine the Public IP.`nRun the command with -StartIfVMIsNotRunning flag" -f $VMName)
break
}
elseif ([string]::IsNullOrEmpty($PIP.IPAddressToString) -and $ISVMRunning -eq $true)
{
Write-Verbose -Message $("No public ip id assigned to this {0} VM." -f $VMName)
break
}

If the ‘-ConnectRDP’ flag is enabled then the remote desktop connection will be established (only when the default port for RDP is allowed in the inbound security rules) otherwise it simply returns the public ip address…


# Connect the VM when -ConnectRDP flag is enabled and VM is running
if ($ConnetRDP -and $ISVMRunning)
{
Invoke-Expression "mstsc.exe /v $($PIP.IPAddressToString)"
break
}

# Just return the IP address when no flags are enabled
return, $PIP.IPAddressToString

And lets see some examples…


.EXAMPLE

C:\GitRepo> .\Get-ARMVMPIP.ps1 -ResourceGroupName lab-rg -Name Workstation
xxx.xxx.xxx.xxx

Returns the public ip address when the VM is running or the VM is deallocated but the publicIPAllocationMethod is set to 'Static'.

.EXAMPLE

C:\GitRepo> $VM = Get-AzureRmVM -ResourceGroupName lab-rg -Name Workstation
C:\GitRepo> $VM | .\Get-ARMVMPIP.ps1
xxx.xxx.xxx.xxx

Returns the public ip address when the VM is running or the VM is deallocated but the publicIPAllocationMethod is set to 'Static'.

.EXAMPLE

C:\GitRepo> .\Get-ARMVMPIP.ps1 -ResourceGroupName lab-rg -Name Workstation -StartIfVMIsNotRunning
xxx.xxx.xxx.xxx

Returns the public ip address when the VM is running or starts the VM if it is not running and returns the public ip.

.EXAMPLE

C:\GitRepo> .\Get-ARMVMPIP.ps1 -ResourceGroupName lab-rg -Name Workstation -ConnectRDP

# Doesn't return any output simply connects to RDP session

Connect to RDP session when the VM is running

.EXAMPLE

C:\GitRepo> .\Get-ARMVMPIP.ps1 -ResourceGroupName lab-rg -Name Workstation -ConnectRDP

# Doesn't return any output simply connects to RDP session

Connect to RDP session when the VM is running and if the VM is not running it will start and establish the RDP session.

The complete code is available in my git repository https://github.com/kpatnayakuni/PowerShell/blob/master/Get-ARMVMPIP.ps1