Src/Private/Report/Get-AbrAzNetworkVirtualAppliance.ps1
|
function Get-AbrAzNetworkVirtualAppliance { <# .SYNOPSIS Used by As Built Report to retrieve Azure Network Virtual Appliance information. .DESCRIPTION Identifies third-party Network Virtual Appliances (NVAs) deployed in an Azure subscription by inspecting VM marketplace image publisher metadata and optional resource tags. Renders a summary table at InfoLevel 1, per-NVA detail lists at InfoLevel 2, and associated UDR route table cross-reference at InfoLevel 3. .NOTES Version: 0.1.0 Author: Tim Carman Twitter: @tpcarman Github: tpcarman .EXAMPLE .LINK #> [CmdletBinding()] param () begin { $LocalizedData = $reportTranslate.GetAbrAzNetworkVirtualAppliance Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.NetworkVirtualAppliance) } process { Try { if ($InfoLevel.NetworkVirtualAppliance -gt 0) { #region --- NVA publisher list --- # Default well-known NVA publishers. Overridden by Options.NvaPublishers when set. $DefaultNvaPublishers = @( 'paloaltonetworks', 'fortinet', 'cisco', 'checkpoint', 'f5-networks', 'barracudanetworks', 'sonicwall-inc', 'juniper-networks', 'viptela', 'riverbed' ) $NvaPublishers = if ($Options.NvaPublishers -and $Options.NvaPublishers.Count -gt 0) { $Options.NvaPublishers } else { $DefaultNvaPublishers } $NvaTagKey = if ($Options.NvaTag) { ($Options.NvaTag -split '=')[0].Trim() } else { $null } $NvaTagValue = if ($Options.NvaTag -and $Options.NvaTag -contains '=') { ($Options.NvaTag -split '=',2)[1].Trim() } else { $null } #endregion Write-PScriboMessage $LocalizedData.Collecting #region --- Pre-collect route tables and load balancers for UDR cross-reference (InfoLevel 3) --- $AllRouteTables = @() $AllLoadBalancers = @() if ($InfoLevel.NetworkVirtualAppliance -ge 3) { $AllRouteTables = Get-AzRouteTable -ErrorAction SilentlyContinue # NVA HA pairs are commonly deployed behind an Internal Load Balancer, with UDRs # pointing at the ILB's frontend IP rather than any individual appliance NIC. $AllLoadBalancers = Get-AzLoadBalancer -ErrorAction SilentlyContinue } #endregion #region --- Collect all VMs and filter to NVAs --- $AzVms = Get-AzVM -Status | Sort-Object Name $NvaVms = @() foreach ($AzVm in $AzVms) { $ImageRef = $AzVm.StorageProfile.ImageReference $IsNvaByImg = $ImageRef.Publisher -and ($NvaPublishers -contains $ImageRef.Publisher.ToLower()) $IsNvaByTag = $false if ($NvaTagKey) { $TagVal = $AzVm.Tags[$NvaTagKey] $IsNvaByTag = if ($NvaTagValue) { $TagVal -eq $NvaTagValue } else { $null -ne $TagVal } } if (-not ($IsNvaByImg -or $IsNvaByTag)) { continue } Write-PScriboMessage ($LocalizedData.Processing -f $AzVm.Name) #region --- Resolve primary NIC --- $PrimaryNicId = ($AzVm.NetworkProfile.NetworkInterfaces | Where-Object { $_.Primary } | Select-Object -First 1).Id if (-not $PrimaryNicId) { $PrimaryNicId = $AzVm.NetworkProfile.NetworkInterfaces[0].Id } $PrimaryNicName = $PrimaryNicId.Split('/')[-1] $PrimaryNicRg = $PrimaryNicId.Split('/')[4] $PrimaryNic = Get-AzNetworkInterface -Name $PrimaryNicName -ResourceGroupName $PrimaryNicRg -ErrorAction SilentlyContinue $PrivateIp = $PrimaryNic.IpConfigurations[0].PrivateIpAddress $VNetSubnet = if ($PrimaryNic.IpConfigurations[0].Subnet.Id) { $Parts = $PrimaryNic.IpConfigurations[0].Subnet.Id.Split('/') "$($Parts[$Parts.IndexOf('virtualNetworks') + 1]) / $($Parts[-1])" } else { '--' } $AllNicNames = ($AzVm.NetworkProfile.NetworkInterfaces | ForEach-Object { $_.Id.Split('/')[-1] }) -join ', ' #endregion #region --- Vendor display name --- $VendorDisplay = switch ($ImageRef.Publisher.ToLower()) { 'paloaltonetworks' { 'Palo Alto Networks' } 'fortinet' { 'Fortinet' } 'cisco' { 'Cisco' } 'checkpoint' { 'Check Point' } 'f5-networks' { 'F5 Networks' } 'barracudanetworks' { 'Barracuda Networks' } 'sonicwall-inc' { 'SonicWall' } 'juniper-networks' { 'Juniper Networks' } 'viptela' { 'Cisco Viptela (SD-WAN)' } 'riverbed' { 'Riverbed' } default { $ImageRef.Publisher } } if (-not $ImageRef.Publisher) { $VendorDisplay = $LocalizedData.TagIdentified } #endregion #region --- Associated UDR route tables (InfoLevel 3) --- $AssociatedRouteTables = @() if ($InfoLevel.NetworkVirtualAppliance -ge 3) { # Match against every private IP owned by this NVA (all NICs, not just the primary), # plus the frontend private IP of any Load Balancer whose backend pool includes one of # those NICs, since HA NVA pairs are commonly fronted by an Internal Load Balancer and # UDRs route to the ILB's frontend IP rather than to an individual appliance NIC. $MatchIps = [System.Collections.Generic.HashSet[string]]::new() foreach ($NicRef in $AzVm.NetworkProfile.NetworkInterfaces) { $Nic = if ($NicRef.Id -eq $PrimaryNicId) { $PrimaryNic } else { Get-AzNetworkInterface -Name $NicRef.Id.Split('/')[-1] -ResourceGroupName $NicRef.Id.Split('/')[4] -ErrorAction SilentlyContinue } foreach ($IpConfig in $Nic.IpConfigurations) { if ($IpConfig.PrivateIpAddress) { [void]$MatchIps.Add($IpConfig.PrivateIpAddress) } foreach ($Lb in $AllLoadBalancers) { foreach ($Pool in $Lb.BackendAddressPools) { $IsPoolMember = ($Pool.BackendIpConfigurations.Id -contains $IpConfig.Id) -or ($Pool.LoadBalancerBackendAddresses.NetworkInterfaceIpConfiguration.Id -contains $IpConfig.Id) -or ($Pool.LoadBalancerBackendAddresses.IpAddress -contains $IpConfig.PrivateIpAddress) if ($IsPoolMember) { foreach ($Frontend in $Lb.FrontendIpConfigurations) { if ($Frontend.PrivateIpAddress) { [void]$MatchIps.Add($Frontend.PrivateIpAddress) } } } } } } } foreach ($Rt in $AllRouteTables) { $MatchingRoutes = $Rt.Routes | Where-Object { $_.NextHopType -eq 'VirtualAppliance' -and $MatchIps.Contains($_.NextHopIpAddress) } if ($MatchingRoutes) { foreach ($Route in $MatchingRoutes) { $AssociatedRouteTables += [PSCustomObject][Ordered]@{ $LocalizedData.RouteTable = $Rt.Name $LocalizedData.ResourceGroup = $Rt.ResourceGroupName $LocalizedData.RouteName = $Route.Name $LocalizedData.AddressPrefix = $Route.AddressPrefix } } } } } #endregion $NvaVms += [PSCustomObject]@{ Name = $AzVm.Name ResourceGroup = $AzVm.ResourceGroupName Location = $AzLocationLookup."$($AzVm.Location)" Subscription = "$($AzSubscriptionLookup.(($AzVm.Id).split('/')[2]))" SubscriptionID = ($AzVm.Id).split('/')[2] Vendor = $VendorDisplay Publisher = if ($ImageRef.Publisher) { $ImageRef.Publisher } else { '--' } Offer = if ($ImageRef.Offer) { $ImageRef.Offer } else { '--' } Sku = if ($ImageRef.Sku) { $ImageRef.Sku } else { '--' } ImageVersion = if ($ImageRef.ExactVersion) { $ImageRef.ExactVersion } elseif ($ImageRef.Version) { $ImageRef.Version } else { '--' } Status = Switch ($AzVm.PowerState) { 'Vm deallocated' { $LocalizedData.Deallocated } 'Vm running' { $LocalizedData.Running } default { $AzVm.PowerState } } Size = $AzVm.HardwareProfile.VmSize PrivateIPAddress = if ($PrivateIp) { $PrivateIp } else { '--' } VirtualNetworkSubnet = $VNetSubnet NetworkInterfaces = $AllNicNames Tags = if ($AzVm.Tags -and $AzVm.Tags.Count -gt 0) { ($AzVm.Tags.GetEnumerator() | ForEach-Object { "$($_.Key) = $($_.Value)" }) -join [System.Environment]::NewLine } else { $LocalizedData.None } AssociatedRouteTables = $AssociatedRouteTables DetectedBy = if ($IsNvaByImg -and $IsNvaByTag) { $LocalizedData.DetectedBoth } elseif ($IsNvaByImg) { $LocalizedData.DetectedByPublisher } else { $LocalizedData.DetectedByTag } } } #endregion if ($NvaVms) { Section -Style Heading4 $LocalizedData.Heading { if ($Options.ShowSectionInfo) { Paragraph $LocalizedData.SectionInfo BlankLine } if ($InfoLevel.NetworkVirtualAppliance -ge 2) { #region --- InfoLevel 2+: per-NVA detail --- Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) BlankLine foreach ($Nva in $NvaVms) { Section -Style NOTOCHeading5 -ExcludeFromTOC $Nva.Name { $InObj = [Ordered]@{ $LocalizedData.Name = $Nva.Name $LocalizedData.ResourceGroup = $Nva.ResourceGroup $LocalizedData.Location = $Nva.Location $LocalizedData.Subscription = $Nva.Subscription $LocalizedData.SubscriptionID = $Nva.SubscriptionID $LocalizedData.Vendor = $Nva.Vendor $LocalizedData.Publisher = $Nva.Publisher $LocalizedData.Offer = $Nva.Offer $LocalizedData.Sku = $Nva.Sku $LocalizedData.ImageVersion = $Nva.ImageVersion $LocalizedData.Status = $Nva.Status $LocalizedData.Size = $Nva.Size $LocalizedData.PrivateIPAddress = $Nva.PrivateIPAddress $LocalizedData.VirtualNetworkSubnet = $Nva.VirtualNetworkSubnet $LocalizedData.NetworkInterfaces = $Nva.NetworkInterfaces $LocalizedData.DetectedBy = $Nva.DetectedBy $LocalizedData.Tags = $Nva.Tags } $TableParams = @{ Name = "$($LocalizedData.TableHeading) - $($Nva.Name)" List = $true ColumnWidths = 40, 60 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } [PSCustomObject]$InObj | Table @TableParams #region --- HealthCheck: NVA deallocated --- if ($HealthCheck.NetworkVirtualAppliance.Status) { if ($Nva.Status -eq $LocalizedData.Deallocated) { [PSCustomObject]$InObj | Set-Style -Style Critical -Property $LocalizedData.Status } } #endregion #region --- InfoLevel 3: associated UDR route tables --- if ($InfoLevel.NetworkVirtualAppliance -ge 3) { if ($Nva.AssociatedRouteTables -and $Nva.AssociatedRouteTables.Count -gt 0) { Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.AssociatedRoutes { $RouteTableParams = @{ Name = "$($LocalizedData.AssociatedRoutes) - $($Nva.Name)" List = $false ColumnWidths = 25, 25, 25, 25 } if ($Report.ShowTableCaptions) { $RouteTableParams['Caption'] = "- $($RouteTableParams.Name)" } $Nva.AssociatedRouteTables | Table @RouteTableParams } } else { Paragraph $LocalizedData.NoAssociatedRoutes } } #endregion } } #endregion } else { #region --- InfoLevel 1: summary table --- Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) BlankLine $NvaSummary = @() foreach ($Nva in $NvaVms) { $InObj = [Ordered]@{ $LocalizedData.Name = $Nva.Name $LocalizedData.ResourceGroup = $Nva.ResourceGroup $LocalizedData.Location = $Nva.Location $LocalizedData.Vendor = $Nva.Vendor $LocalizedData.Offer = $Nva.Offer $LocalizedData.Status = $Nva.Status $LocalizedData.PrivateIPAddress = $Nva.PrivateIPAddress } $NvaSummary += [PSCustomObject]$InObj } $TableParams = @{ Name = "$($LocalizedData.TableHeadings) - $($AzSubscription.Name)" List = $false ColumnWidths = 20, 16, 14, 14, 14, 10, 12 } if ($Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $NvaSummary | Table @TableParams if ($HealthCheck.NetworkVirtualAppliance.Status) { $NvaSummary | Where-Object { $_.$($LocalizedData.Status) -eq $LocalizedData.Deallocated } | Set-Style -Style Critical -Property $LocalizedData.Status } #endregion } } } } } Catch { Write-PScriboMessage -IsWarning $($_.Exception.Message) } } end {} } |