0

I am new to PS.... trying to get NSGs in a given subscription (and once this works to do this for all subscriptions) to show the following properties (NSG Name, Location, Resource Group, Subnet, NIC).

I am using the below script from Getting list of NSG and corresponding Subnet or NIC but it lists same information for each NSG multiple times equal to the number of NSGs in the subscription so it has to be something wrong in the script

$azNsgs = Get-AzNetworkSecurityGroup
       
 foreach ( $azNsg in $azNsgs ) {

 if ($azNsg.Subnets.Id -ne $null) {

     $NsgSubnets = $azNsg.Subnets.Id.Split('/')[-1]

}
         Get-AzNetworkSecurityGroup | `
            Select-Object `
            @{name = 'NSG Name'; expression = {$azNsg.Name} },  `
            @{name = 'Location'; expression = {$azNsg.Location} }, `
            @{name = 'Resource Group Name'; expression = {$azNsg.ResourceGroupName} },  `
            @{name = 'Subnets'; expression = $NsgSubnets } 
       
}

Also would like the script to ignore null values for NIC/Subnet as some NSGs would be assigned to Subnets whilst others to NICs Finally an NSG could be assigned to multiple subnets/NICs so how do I get the $azNsg.Subnets.Id.Split('/')[-1] part working for multiple entries in Subnets.Id or NetworkInterfaces.Id and not just the last one ?

Thanks

  • You do not need to call `Get-AzNetworkSecurityGroup` the second time inside of your `foreach` loop. Just use `$azNsg | Select-Object ....`. – AdminOfThings Jan 13 '21 at 15:09
  • Many thanks @AdminOfThings.. that seems to have solved that part.. could you help me please with the second part of the query where I want to see subnets and/or NICs associated with each NSG and it should list all subnets/nics not just the last one – ByteServe Jan 13 '21 at 15:22
  • Index `[-1]` gets the last element of an array. If you don't want only the last element, then you should remove that index. Since you are using an `if` statement to set `$NsgSubnets`, it is not reset for when there are no subnets. The first line of your `foreach` needs to be something like `$NsgSubnets = $null`. – AdminOfThings Jan 13 '21 at 15:23
  • After looking at the linked post, I think I understand more of the issue. The subnet ID is a path and you only want the leaf of that path (the name only). You could try `$NsgSubnets = $azNsg.Subnets.foreach({$_.Id.Split('/')[-1]})` – AdminOfThings Jan 13 '21 at 15:30

1 Answers1

0

You can do the following:

$azNsgs = Get-AzNetworkSecurityGroup
       
    foreach ( $azNsg in $azNsgs ) {

        $NsgSubnets = $null

        if (!$azNsg.Subnets.Id) {
            $NsgSubnets = $azNsg.Subnets.foreach({$_.Id.Split('/')[-1]})
        }

         $azNsg |
            Select-Object @{name = 'NSG Name'; expression = {$_.Name}},
                @{name = 'Location'; expression = {$_.Location}},
                @{name = 'Resource Group Name'; expression = {$_.ResourceGroupName}},  
                @{name = 'Subnets'; expression = {$NsgSubnets -join ','}}
       
    }

Overall improvements include:

  • You only need to run Get-AzNetworkSecurityGroup once since you are storing its output into a variable. You can simply retrieve its contents from the variable. This makes the code execute faster.
  • Since your objects could have multiple subnets, you need to handle the case when $azNsg.Subnets is an array of non-null objects. Using the foreach() method, you can process code against each element of that array. When PowerShell fully enumerates array output (as it does in the case without foreach()), your multiple subnet arrays become one large array on the final output. Then [-1] only returns the very last Id value.
  • Setting $NsgSubnets inside of an if statement without an else statement leads to bad data later in the code execution. If the network has a subnet, $NsgSubnets will be set and returned properly. However, if the next network has no subnet, you are not updating the value of $NsgSubnets. Therefore, it will output the previous network's subnet information in your Select-Object command.
  • You don't always need backticks for continuation. | and , separating elements automatically supports continuation. See Natural Line Continuations.
AdminOfThings
  • 23,946
  • 4
  • 17
  • 27
  • I tried that but it does not return any subnets even when some of the NSGs (not all) have subnets associated – ByteServe Jan 13 '21 at 16:40
  • Maybe the subnets need to be joined as a single string. I added code to do that. If that doesn't work, please show a sample output of `$aznsg.subnets`. I don't have a way of verifying this. – AdminOfThings Jan 13 '21 at 17:04
  • I could not get anything from $aznsg.subnets however I ran the below to query the NSG that is assigned to multiple subnets `Get-AzNetworkSecurityGroup -Name { "Id": "/subscriptions/0000000.....VNET-01/subnets/SUB-NONPROD-01", "IpAllocations": [] }, { "Id": "/subscriptions/000000000..../VNET-01/subnets/SUB-PROD-01", "IpAllocations": [] ` – ByteServe Jan 13 '21 at 17:39
  • ...based on the above I would expect SUB-NONPROD-01 and SUB-PROD-01 to be shown in the subnet column – ByteServe Jan 13 '21 at 18:11
  • I have got the data by using `@{name = 'Subnets'; expression = { $NsgSubnets | ForEach ({$_.id.split('/')[-1] }) } }` The output is on separate lines subnet1 subnet2 subnet3 subnet4 However when trying to export the above subnets into a singe cell using export-excel, I get System.Object[]. Surprisingly this works fine if I use export-csv so I am assuming its excel that's the culprit here ? `Export-Excel -Path "$($home)\Documents\Work\Powershell\NSG-Summary-v12.xlsx" -WorksheetName ($azsub.Name) -Append -AutoSize -FreezeTopRow -BoldTopRow -AutoFilter` Any ideas ? – ByteServe Jan 15 '21 at 11:43