How to find and Delete orphan public ip in azure using powershell - azure

How to list and remove unused (orphanip) public ip address "such as search if the ip is not associated to any Vm or Networkinterface card find and then delete" in azure using powershell azure automation runbook.
Getting this error "Method 'get_SerializationSettings' in type 'Microsoft.Azure.Management.Internal.Resources.ResourceManagementClient' from assembly 'Microsoft.Azure.Commands.ResourceManager.Common, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' does not have an implementation."
Run Login-AzureRmAccount to login.
[CmdletBinding(SupportsShouldProcess=$true,
   ConfirmImpact="High")]
Param
(
# Specifies the name of the resource group from which Public IP Addresses are to be retrieved.
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[string]$ResourceGroup,
# Only lists Azure Network Interfaces that are not linked to an existing Azure Virtual Machine
[switch]$ListOnly
)
Begin
{
If (AzureRmResourceGroup -Name $ResourceGroup -ErrorAction SilentlyContinue )
{
$az_publicipaddress = Get-AzureRmPublicIpAddress -ResourceGroupName $ResourceGroup
$RemAzPublicIP = $az_publicipaddress | Where-Object {$_.IpConfiguration -eq $null}
}
Else
{
Write-Error "Provided resource group does not exist: $ResourceGroup"
Throw
}
}
Process
{
$removed = #()
If ($PSBoundParameters.ContainsKey("ListOnly"))
{
$RemAzPublicIP | Select-Object Name,ResourceGuid
}
Else
{
ForEach($pi in $RemAzPublicIP)
{
if ($pscmdlet.ShouldProcess("Deleting NetworkInterface $($pi.Name)"))
{
Write-Output "Removing Public IP Address without Virtual Machine association: $($pi.Name)"
  Remove-AzureRmPublicIpAddress -Name "$($pi.name)" -ResourceGroupName $ResourceGroup
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name Name -Value $($pi.Name)
$object | Add-Member -MemberType NoteProperty -Name ResourceGuid -Value $($pi.ResourceGuid)
$removed += $object
}
}
}
}
End
{
# List the removed objects
$removed
}

You can utilise Get-AzNetworkInterface to return all NICs within your current context.
You would have to filter the results to see which were not attached to a virtual machine.
# This will return NICs which aren't associated to a VM
$orphanedNics = Get-AzNetworkInterface | Where-Object VirtualMachine -eq $null
If you have a lot of resources to check then you could use Search-AzGraph from the Az.ResourceGraph module to perform the search.
$query = '
Resources
| where type has "microsoft.network/networkinterfaces"
| where properties !has "virtualmachine"'
$orphanedNics = Search-AzGraph -Query $query
Once you have those results and validated it's correct you can then use Remove-AzNetworkInterface to delete.

Related

Assistance with looping through multiple subscriptions

I'm using the below script from http://vcloud-lab.com/entries/microsoft-azure/get-azure-virtual-machine-backup-reports-using-powershell to pull Azure VM backup details. Currently I have to run the script against each subscription, I would love to have it loop though all subscriptions.
I've been trying to get it working using this example https://www.jpaul.me/2019/05/azure-automation-how-to-quickly-work-with-many-subscriptions/ but I'm new to powershell and am struggling. Any suggestions would be really appreciated.
[CmdletBinding(SupportsShouldProcess=$True,
ConfirmImpact='Medium',
HelpURI='http://vcloud-lab.com',
DefaultParameterSetName = 'AllVirtualMachines'
)]
<#
.SYNOPSIS
Collect Azure VM Backup Information
.DESCRIPTION
This Script collects Azure Virtual Machine Backup Recovery service vault information, This report includes the complete backup status Information of VM.
.PARAMETER AllVirtualMachines
Collect Backup information of the all Azure Virtual Machines, This is default parameter.
.PARAMETER VirtualMachineList
You can specify for which virtual machine you want backup information.
.INPUTS
None. Provides virtual machine information.
.OUTPUTS
Generate Backup information. You can pipe information to Export-CSV.
.EXAMPLE
PS> .\Get-AzVMBackupInformation.ps1
VM_Name : vcloud-lab-vm01
VM_Location : uksouth
VM_ResourceGroupName : VCLOUD-LAB.COM
VM_BackedUp : True
VM_RecoveryVaultName : vault828
VM_RecoveryVaultPolicy : DailyPolicy-kosrnox0
VM_BackupHealthStatus : Passed
VM_BackupProtectionStatus : Healthy
VM_LastBackupStatus : Completed
VM_LastBackupTime : 27-05-2021 19:32:34
VM_BackupDeleteState : NotDeleted
VM_BackupLatestRecoveryPoint : 27-05-2021 19:32:37
VM_Id : /subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/VCLOUD-LAB.COM/providers/Microsoft.Compute/virtualMachines/vcloud-lab-vm01
RecoveryVault_ResourceGroupName : vCloud-lab.com
RecoveryVault_Location : uksouth
RecoveryVault_SubscriptionId : /subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vCloud-lab.com/providers/Microsoft.RecoveryServices/vaults/vault828
.EXAMPLE
PS> .\Get-AzVMBackupInformation.ps1 -AllVirtualMachines
This produces same result as .\Get-AzVMBackupInformation.ps1 from all VMs
.EXAMPLE
PS> .\Get-AzVMBackupInformation.ps1 -VirtualMachineList
Provide either single virtual machine name or in list
.LINK
Online version: http://vcloud-lab.com
.LINK
Get-AzVMBackupInformation.ps1
#>
Param
(
[parameter(Position=0, ParameterSetName = 'AllVMs' )]
[Switch]$AllVirtualMachines,
[parameter(Position=0, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True, ParameterSetName = 'VM' )]
[alias('Name')]
[String[]]$VirtualMachineList
) #Param
Begin
{
#Collecing Azure virtual machines Information
Write-Host "Collecing Azure virtual machine Information" -BackgroundColor DarkGreen
if (($PSBoundParameters.ContainsKey('AllVirtualMachines')) -or ($PSBoundParameters.Count -eq 0))
{
$vms = Get-AzVM
} #if ($PSBoundParameters.ContainsKey('AllVirtualMachines'))
elseif ($PSBoundParameters.ContainsKey('VirtualMachineList'))
{
$vms = #()
foreach ($vmname in $VirtualMachineList)
{
$vms += Get-AzVM -Name $vmname
} #foreach ($vmname in $VirtualMachineList)
} #elseif ($PSBoundParameters.ContainsKey('VirtualMachineList'))
#Collecing All Azure backup recovery vaults Information
Write-Host "Collecting all Backup Recovery Vault information" -BackgroundColor DarkGreen
$backupVaults = Get-AzRecoveryServicesVault
} #Begin
Process
{
$vmBackupReport = [System.Collections.ArrayList]::new()
foreach ($vm in $vms)
{
$recoveryVaultInfo = Get-AzRecoveryServicesBackupStatus -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Type 'AzureVM'
if ($recoveryVaultInfo.BackedUp -eq $true)
{
Write-Host "$($vm.Name) - BackedUp : Yes"
#Backup Recovery Vault Information
$vmBackupVault = $backupVaults | Where-Object {$_.ID -eq $recoveryVaultInfo.VaultId}
#Backup recovery Vault policy Information
$container = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVM -VaultId $vmBackupVault.ID -FriendlyName $vm.Name #-Status "Registered"
$backupItem = Get-AzRecoveryServicesBackupItem -Container $container -WorkloadType AzureVM -VaultId $vmBackupVault.ID
} #if ($recoveryVaultInfo.BackedUp -eq $true)
else
{
Write-Host "$($vm.Name) - BackedUp : No" -BackgroundColor DarkRed
$vmBackupVault = $null
$container = $null
$backupItem = $null
} #else if ($recoveryVaultInfo.BackedUp -eq $true)
[void]$vmBackupReport.Add([PSCustomObject]#{
VM_Name = $vm.Name
VM_Location = $vm.Location
VM_ResourceGroupName = $vm.ResourceGroupName
VM_BackedUp = $recoveryVaultInfo.BackedUp
VM_RecoveryVaultName = $vmBackupVault.Name
VM_RecoveryVaultPolicy = $backupItem.ProtectionPolicyName
VM_BackupHealthStatus = $backupItem.HealthStatus
VM_BackupProtectionStatus = $backupItem.ProtectionStatus
VM_LastBackupStatus = $backupItem.LastBackupStatus
VM_LastBackupTime = $backupItem.LastBackupTime
VM_BackupDeleteState = $backupItem.DeleteState
VM_BackupLatestRecoveryPoint = $backupItem.LatestRecoveryPoint
VM_Id = $vm.Id
RecoveryVault_ResourceGroupName = $vmBackupVault.ResourceGroupName
RecoveryVault_Location = $vmBackupVault.Location
RecoveryVault_SubscriptionId = $vmBackupVault.ID
}) #[void]$vmBackupReport.Add([PSCustomObject]#{
} #foreach ($vm in $vms)
} #Process
end
{
$vmBackupReport
} #end
You can try this sample script from the MS doc for looping through multiple subscriptions.
Connect-AzAccount
$SubscriptionList = Get-AzSubscription
foreach ($Id in $SubscriptionList)
{
#Provide the subscription Id where the VMs reside
$subscriptionId = $Id
#Provide the name of the csv file to be exported
$reportName = "myReport.csv"
Select-AzSubscription $subscriptionId
$report = #()
$vms = Get-AzVM
$publicIps = Get-AzPublicIpAddress
$nics = Get-AzNetworkInterface | ?{ $_.VirtualMachine -NE $null}
foreach ($nic in $nics)
{
$info = "" | Select VmName, ResourceGroupName, Region, VmSize, VirtualNetwork, Subnet, PrivateIpAddress, OsType, PublicIPAddress, NicName, ApplicationSecurityGroup, subscriptionId
$vm = $vms | ? -Property Id -eq $nic.VirtualMachine.id
foreach($publicIp in $publicIps)
{
if($nic.IpConfigurations.id -eq $publicIp.ipconfiguration.Id)
{
$info.PublicIPAddress = $publicIp.ipaddress
}
}
$info.subscriptionId = $subscriptionId
$info.OsType = $vm.StorageProfile.OsDisk.OsType
$info.VMName = $vm.Name
$info.ResourceGroupName = $vm.ResourceGroupName
$info.Region = $vm.Location
$info.VmSize = $vm.HardwareProfile.VmSize
$info.VirtualNetwork = $nic.IpConfigurations.subnet.Id.Split("/")[-3]
$info.Subnet = $nic.IpConfigurations.subnet.Id.Split("/")[-1]
$info.PrivateIpAddress = $nic.IpConfigurations.PrivateIpAddress
$info.NicName = $nic.Name
$info.ApplicationSecurityGroup = $nic.IpConfigurations.ApplicationSecurityGroups.Id
$report+=$info
}
$report | ft subscriptionId, VmName, ResourceGroupName, Region, VmSize, VirtualNetwork, Subnet, PrivateIpAddress, OsType, PublicIPAddress, NicName, ApplicationSecurityGroup
$report | Export-CSV "$home/$reportName"
}
References: Collect details about all VMs in a subscription with PowerShell - Azure Virtual Machines | Microsoft Docs , Iterate through subscriptions using an Array to avoid manual work · Issue #50670 · MicrosoftDocs/azure-docs · GitHub and powershell - How to loop through multiple Azure subscriptions on Azure Pipelines Yaml? - Stack Overflow

How to create an Azure Network Security Group Flow log with Azure PowerShell

I want to create a NSG flow log for the network security group of a given Virtual Machine and link to a given Storage Account with PowerShell.
How can I achieve this?
This can be achieved with this sequence of operations:
determine the NSG linked to a Virtual Machine
get or create a `NetworkWatcher for the location of the NSG
find a suitable storage account
set a Flow Log configuration, if there is none existing
param(
# RegEx pattern to find your first VM in your current subscription
[Parameter(Mandatory = $true, Position = 1)]
[string]$vmNamePattern,
# RegEx pattern to find a storage account in your current subscription
[Parameter(Mandatory = $true, Position = 2)]
[string]$storageNamePattern
)
$vm = Get-AzVM | Where-Object { $_.Name -match $vmNamePattern } | Select-Object -First 1
$nic = Get-AzNetworkInterface -ResourceId $vm.NetworkProfile.NetworkInterfaces[0].Id
$sn = Get-AzVirtualNetworkSubnetConfig -ResourceId $nic.IpConfigurations[0].Subnet.Id
$nsgRes = Get-AzResource -ResourceId $sn.NetworkSecurityGroup.Id
$nsg = Get-AzNetworkSecurityGroup -ResourceGroupName $nsgRes.ResourceGroupName -Name $nsgRes.ResourceName
# create or get NetworkWatcher
$nw = Get-AzNetworkWatcher -ResourceGroupName NetworkWatcherRg | ? { $_.Location -eq $nsg.Location }
if (!$nw) {
New-AzNetworkWatcher -ResourceGroupName NetworkWatcherRg -Location $nsg.Location -Name $("NetworkWatcher_" + $nsg.Location)
$nw = Get-AzNetworkWatcher -ResourceGroupName NetworkWatcherRg | ? { $_.Location -eq $nsg.Location }
}
# detect first viable storage account
$storageAccount = Get-AzStorageAccount | Where-Object { $_.StorageAccountName -match $storageNamePattern -and $_.PrimaryEndpoints.Blob -match "^http" } | Select-Object -First 1
# get or set NSG flow log if not yet established
$fl = Get-AzNetworkWatcherFlowLogStatus -NetworkWatcher $nw -TargetResourceId $nsg.Id
if (!$fl) {
# https://learn.microsoft.com/de-de/azure/network-watcher/network-watcher-nsg-flow-logging-powershell
Set-AzNetworkWatcherConfigFlowLog -NetworkWatcher $nw -TargetResourceId $nsg.Id -StorageAccountId $storageAccount.Id -EnableFlowLog $true -FormatType Json -FormatVersion 2
}

Output of Azure subnets with links to attached VNet, route table and NSG

I'm currently working on a script that gives me the output of every Subnet in an Azure Subscription, with links to the VNet, NSG, and the Route Table. The Route Table Name is currently missing in the script, but I want to focus on fixing the NSG right now.
This is what my Script looks like:
$VNets = Get-AzVirtualNetwork
$NSG = Get-AzNetworkSecurityGroup
$VNets | ForEach-Object {
$VNettemp = $_
$result = $_.Subnets | Select-Object #{Label="Subnet Name";Expression={$_.Name}},#{Label="Subnet";Expression={$_.AddressPrefix}}
$_ | ForEach-Object {
$result | Add-Member -Name "VNet Name" -Value $_.Name -MemberType NoteProperty
}
if ($_.Subnets.NetworksecurityGroup -ne "null"){
$NSG | ForEach-Object{
if ($VNettemp.Subnets.Id -contains $_.Subnets.Id ){
$result | Add-Member -Name "NSG Name" -Value $_.name -MemberType NoteProperty -Force
}
}
}
return $result
}
The output looks like this:
Subnet Name Subnet VNet Name NSG Name
----------- ------ --------- --------
default-subnet 10.10.10.0/28 vnet-ine-test test-nsg
vnet-ine-test-snet-test 10.10.0.0/24 vnet-ine-test test-nsg
default 10.0.0.0/24 vnet-chn-docker vnet-chn-docker-nsg
vnet-test-subnet 10.0.1.0/24 vnet-chn-docker vnet-chn-docker-nsg
The desired output would look like this because 'default-subnet' and 'vnet-test-subnet' have no NSG attached:
Subnet Name Subnet VNet Name NSG Name
----------- ------ --------- --------
default-subnet 10.10.10.0/28 vnet-ine-test
vnet-ine-test-snet-test 10.10.0.0/24 vnet-ine-test test-nsg
default 10.0.0.0/24 vnet-chn-docker vnet-chn-docker-nsg
vnet-test-subnet 10.0.1.0/24 vnet-chn-docker
Does anybody know how to fix the output? I tried it with an else statement that fills in an empty value for "NSG Name" but then the name gets canceled entirely for the whole VNet.
Thanks for the Help!
Regarding the issue, please refer to the following script
$VNets = Get-AzVirtualNetwork
$NSG = Get-AzNetworkSecurityGroup
$resports=#()
$info = #{ "Subnet Name"=""; "Subnet"=""; "VNet Name"="" ; "NSG Name"=""}
foreach($VNet in $VNets){
$info.'VNet Name'=$VNet.Name
$info.'NSG Name'=$null
Foreach($sub in $VNet.Subnets){
$info.'Subnet Name' =$sub.Name
$info.Subnet=$sub.AddressPrefix
if($sub.NetworkSecurityGroup -ne $null){
$NSG | ForEach-Object{
if ($VNet.Subnets.Id -contains $_.Subnets.Id ){
$info.'NSG Name'=$_.Name
}
}
}
$obj=New-Object PSObject -Property $info
$resports +=$obj
}
}

How to get the list of azure servers having Auto-Shutdown disabled using PowerShell?

I want to get the list of azure servers having auto-shutdown disabled on them, I have the below script but the issue with the script is that it gets the list of RG's under the Subscription GUID but repeats the output after every loop.
Import-AzureRmContext -Path "$PSScriptRoot\AzureProfile.json"
Select-AzureRmSubscription -SubscriptionId {subscriptionId}
[array]$ResourceGroupArray = Get-AzureRMVm | Select-Object -Property ResourceGroupName, Name, VmId
foreach ($resourceGroup in $ResourceGroupArray){
$targetResourceId = (Get-AzureRmVM -ResourceGroupName $resourcegroup.ResourceGroupName -Name $resourceGroup.Name).Id
$shutdownInformation = (Get-AzureRmResource -ResourceGroupName $resourcegroup.ResourceGroupName -ResourceType Microsoft.DevTestLab/schedules -Expandproperties).Properties
Write-Host "ID: " $targetResourceId
$shutdownInformation
The output for each VM is displayed in the following format,
What I want is simple, I want the VM name and its status of Auto-shutdown to be displayed on the screen so that its easy for me to find out which all VM have auto-shutdown currently disabled on them.
Any help related to this would be helpful.
You just need to get the microsoft.devtestlab/schedules resource ID using:
/subscriptions/{subscriptionId}/resourceGroups/{rgName}/providers/microsoft.devtestlab/schedules/shutdown-computevm-{vmName}
Then iterate over all your VMs using Get-AzVM, Get the microsoft.devtestlab/schedules resource using Get-AzResource, then output VM name and status into a table using Format-Table.
$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Set-AzContext -SubscriptionId $subscriptionId
& {
foreach ($vm in Get-AzVM) {
try {
$shutdownResource = Get-AzResource `
-ResourceId "/subscriptions/$subscriptionId/resourceGroups/$($vm.ResourceGroupName)/providers/microsoft.devtestlab/schedules/shutdown-computevm-$($vm.Name)" `
-ErrorAction Stop
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $shutdownResource.Properties.status
}
}
catch {
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $_.Exception.Message
}
}
}
} | Format-Table -AutoSize
To set the context to the correct subscription, we can use Set-AzContext.
The above however is using the latest Az modules. You can do the same using the equivalent AzureRm modules.
$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Set-AzureRmContext -SubscriptionId $subscriptionId
& {
foreach ($vm in Get-AzureRmVM) {
try {
$shutdownResource = Get-AzureRmResource `
-ResourceId "/subscriptions/$subscriptionId/resourceGroups/$($vm.ResourceGroupName)/providers/microsoft.devtestlab/schedules/shutdown-computevm-$($vm.Name)" `
-ErrorAction Stop
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $shutdownResource.Properties.status
}
}
catch {
[PSCustomObject]#{
VMName = $vm.Name
ShutdownStatus = $_.Exception.Message
}
}
}
} | Format-Table -AutoSize
Although I do recommend moving to the Az module since support for AzureRm is ending December 2020. You can read the documentation for more information about this.
The above code should give you an output similar to the following
VMName ShutdownStatus
------ --------------
vm1 Enabled
vm2 Disabled
Update
The Call operator & is used here to run the for loop as a script block. You can read more about this in about_Script_Blocks.
Try something like this to get the auto-shutdown status of all VMs. Instead of trying to get the schedules inside the loop, get all the ones in the subscription and match them based on the VM's full resource Id.
[array]$VMArray = Get-AzureRMVm | Select-Object -Property ResourceGroupName, Name, VmId, Id
$ShutdownInformation = (Get-AzureRmResource -ResourceType Microsoft.DevTestLab/schedules -Expandproperties).Properties
foreach($vm in $VMArray) {
$ShutdownStatus = "Not Configured"
$Schedule = $ShutdownInformation | Where-Object { $_.targetResourceId -eq $vm.Id } | Select -First 1
if($Schedule -ne $null) {
$ShutdownStatus = $Schedule.status
}
Write-Host $vm.VmId $ShutdownStatus
}

List Azure NSGs on Every Azure Subnet

A bit stuck on this one. Going in circles trying to get the NSG Ids listed out for each and every subnet in Azure. It's part of a security control requirement, so we need to list each subnet and then provide the NSG Id with them - to show that each subnet does in fact have an NSG associated with it.
$vnets = (Get-AzVirtualNetwork).Name
$nsgId = (Get-AzVirtualNetwork).Subnets.NetworkSecurityGroup.Id
$snet = (Get-Azvirtualnetwork).Subnets.Name | Out-String
foreach ($vnet in $vnets) {Get-AzVirtualNetworkSubnetConfig -Name $snet -VirtualNetwork $vnets | FL Name,$nsgId}
This is the error I am getting. Just can't get past it.
Get-AzVirtualNetworkSubnetConfig: Cannot convert 'System.Object[]' to the type 'Microsoft.Azure.Commands.Network.Models.PSVirtualNetwork' required by parameter 'VirtualNetwork'. Specified method is not supported.
This should do it.
$vnets = (Get-AzVirtualNetwork)
$objectArr = #()
foreach ($vnet in $vnets) {
foreach ($subnet in $vnet.Subnets) {
if ($subnet.NetworkSecurityGroup -ne $null) {
$NSG = Get-AzResource -ResourceId $subnet.NetworkSecurityGroup.Id
$prop = [ordered]#{
'VNETName' = $vnet.Name
'SubnetName' = $subnet.Name
'NSGName' = $NSG.Name
'Id' = $NSG.Id
}
$obj = New-Object -Type PSCustomObject -Property $prop
$objectArr += $obj
}
}
}
$objectArr | Select-object VNETName, SubnetName, NSGName, Id

Resources