tests/Networking.Module.Tests.ps1
|
#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } #Requires -Modules ImportExcel <# .SYNOPSIS Pester tests for all Networking inventory modules. .DESCRIPTION Tests both Processing and Reporting phases for each Networking module using synthetic mock data. No live Azure authentication is required. .NOTES Author: AzureScout Contributors Version: 1.0.0 Created: 2026-02-24 Phase: 8.3.6, 19.5.13 — VPN / Networking Testing #> # =================================================================== # DISCOVERY-TIME # =================================================================== $NetworkingPath = Join-Path (Split-Path -Parent $PSScriptRoot) 'Modules' 'Public' 'InventoryModules' 'Networking' $NetworkingModules = @( @{ Name = 'VirtualNetwork'; File = 'VirtualNetwork.ps1'; Type = 'microsoft.network/virtualnetworks'; Worksheet = 'Virtual Networks' } @{ Name = 'vNETPeering'; File = 'vNETPeering.ps1'; Type = 'microsoft.network/virtualnetworks'; Worksheet = 'VNet Peerings' } @{ Name = 'VirtualNetworkGateways'; File = 'VirtualNetworkGateways.ps1';Type = 'microsoft.network/virtualnetworkgateways'; Worksheet = 'VPN Gateways' } @{ Name = 'Connections'; File = 'Connections.ps1'; Type = 'microsoft.network/connections'; Worksheet = 'VPN Connections' } @{ Name = 'LoadBalancer'; File = 'LoadBalancer.ps1'; Type = 'microsoft.network/loadbalancers'; Worksheet = 'Load Balancers' } @{ Name = 'ApplicationGateways'; File = 'ApplicationGateways.ps1'; Type = 'microsoft.network/applicationgateways'; Worksheet = 'Application Gateways' } @{ Name = 'NetworkSecurityGroup'; File = 'NetworkSecurityGroup.ps1'; Type = 'microsoft.network/networksecuritygroups'; Worksheet = 'Network Security Groups' } @{ Name = 'PublicIP'; File = 'PublicIP.ps1'; Type = 'microsoft.network/publicipaddresses'; Worksheet = 'Public IPs' } @{ Name = 'RouteTables'; File = 'RouteTables.ps1'; Type = 'microsoft.network/routetables'; Worksheet = 'Route Tables' } @{ Name = 'NetworkInterface'; File = 'NetworkInterface.ps1'; Type = 'microsoft.network/networkinterfaces'; Worksheet = 'Network Interfaces' } @{ Name = 'PrivateEndpoint'; File = 'PrivateEndpoint.ps1'; Type = 'microsoft.network/privateendpoints'; Worksheet = 'Private Endpoints' } @{ Name = 'PrivateDNS'; File = 'PrivateDNS.ps1'; Type = 'microsoft.network/privatednszones'; Worksheet = 'Private DNS Zones' } @{ Name = 'AzureFirewall'; File = 'AzureFirewall.ps1'; Type = 'microsoft.network/azurefirewalls'; Worksheet = 'Azure Firewall' } @{ Name = 'BastionHosts'; File = 'BastionHosts.ps1'; Type = 'microsoft.network/bastionhosts'; Worksheet = 'Bastion Hosts' } @{ Name = 'NATGateway'; File = 'NATGateway.ps1'; Type = 'microsoft.network/natgateways'; Worksheet = 'NAT Gateways' } @{ Name = 'TrafficManager'; File = 'TrafficManager.ps1'; Type = 'microsoft.network/trafficmanagerprofiles'; Worksheet = 'Traffic Manager' } @{ Name = 'VirtualWAN'; File = 'VirtualWAN.ps1'; Type = 'microsoft.network/virtualwans'; Worksheet = 'Virtual WANs' } @{ Name = 'ExpressRoute'; File = 'ExpressRoute.ps1'; Type = 'microsoft.network/expressroutecircuits'; Worksheet = 'ExpressRoute Circuits' } @{ Name = 'NetworkWatchers'; File = 'NetworkWatchers.ps1'; Type = 'microsoft.network/networkwatchers'; Worksheet = 'Network Watchers' } @{ Name = 'Frontdoor'; File = 'Frontdoor.ps1'; Type = 'microsoft.network/frontdoors'; Worksheet = 'Front Doors' } @{ Name = 'PublicDNS'; File = 'PublicDNS.ps1'; Type = 'microsoft.network/dnszones'; Worksheet = 'Public DNS Zones' } ) # =================================================================== # EXECUTION-TIME SETUP # =================================================================== BeforeAll { $script:ModuleRoot = Split-Path -Parent $PSScriptRoot $script:NetworkingPath = Join-Path $script:ModuleRoot 'Modules' 'Public' 'InventoryModules' 'Networking' $script:TempDir = Join-Path $env:TEMP 'AZSC_NetworkingTests' if (Test-Path $script:TempDir) { Remove-Item $script:TempDir -Recurse -Force } New-Item -ItemType Directory -Path $script:TempDir -Force | Out-Null function New-MockNetResource { param([string]$Id, [string]$Name, [string]$Type, [string]$Kind = '', [string]$Location = 'eastus', [string]$RG = 'rg-net', [string]$SubscriptionId = 'sub-00000001', [object]$Props) [PSCustomObject]@{ id = $Id NAME = $Name TYPE = $Type KIND = $Kind LOCATION = $Location RESOURCEGROUP = $RG subscriptionId = $SubscriptionId tags = [PSCustomObject]@{} PROPERTIES = $Props } } $script:MockResources = @() # Virtual Network $script:MockResources += New-MockNetResource -Id '/net/vnet1' -Name 'vnet-prod' ` -Type 'microsoft.network/virtualnetworks' -Props ([PSCustomObject]@{ addressSpace = [PSCustomObject]@{ addressPrefixes = @('10.0.0.0/16') } subnets = @( [PSCustomObject]@{ name = 'default'; properties = [PSCustomObject]@{ addressPrefix = '10.0.0.0/24'; provisioningState = 'Succeeded' } } ) virtualNetworkPeerings = @() enableDdosProtection = $false; provisioningState = 'Succeeded' dhcpOptions = [PSCustomObject]@{ dnsServers = @('168.63.129.16') } }) # VNet Peering (piggybacked on VNet resource) $vnetWithPeering = New-MockNetResource -Id '/net/vnet2' -Name 'vnet-spoke' ` -Type 'microsoft.network/virtualnetworks' -Props ([PSCustomObject]@{ addressSpace = [PSCustomObject]@{ addressPrefixes = @('10.1.0.0/16') } subnets = @() virtualNetworkPeerings = @( [PSCustomObject]@{ name = 'peer-to-hub' properties = [PSCustomObject]@{ remoteVirtualNetwork = [PSCustomObject]@{ id = '/subscriptions/sub-00000001/resourceGroups/rg-net/providers/Microsoft.Network/virtualNetworks/vnet-hub' } remoteAddressSpace = [PSCustomObject]@{ addressPrefixes = @('10.0.0.0/16') } peeringState = 'Connected'; allowVirtualNetworkAccess = $true allowForwardedTraffic = $true; allowGatewayTransit = $false; useRemoteGateways = $true provisioningState = 'Succeeded' } } ) provisioningState = 'Succeeded'; enableDdosProtection = $false }) $script:MockResources += $vnetWithPeering # VPN Gateway $script:MockResources += New-MockNetResource -Id '/net/vpngw1' -Name 'vpngw-prod' ` -Type 'microsoft.network/virtualnetworkgateways' -Props ([PSCustomObject]@{ gatewayType = 'Vpn'; vpnType = 'RouteBased'; sku = [PSCustomObject]@{ name = 'VpnGw1'; tier = 'VpnGw1' } provisioningState = 'Succeeded'; enableBgp = $false; activeActive = $false; enablePrivateIpAddress = $false ipConfigurations = @([PSCustomObject]@{name='ipconf1';properties=[PSCustomObject]@{ publicIPAddress=[PSCustomObject]@{id='/subscriptions/sub-00000001/resourceGroups/rg-net/providers/Microsoft.Network/publicIPAddresses/pip-vpngw'} subnet=[PSCustomObject]@{id='/subscriptions/sub-00000001/resourceGroups/rg-net/providers/Microsoft.Network/virtualNetworks/vnet-prod/subnets/GatewaySubnet'} }}) vpnClientConfiguration = [PSCustomObject]@{ vpnClientAddressPool = [PSCustomObject]@{ addressPrefixes = @('172.16.0.0/24') } vpnClientProtocols = @('IkeV2','SSTP'); vpnAuthenticationTypes = @('Certificate') vpnClientRootCertificates = @(@{name='root1'}); vpnClientRevokedCertificates = @() radiusServers = $null; aadTenant = $null } bgpSettings = [PSCustomObject]@{ asn = 65515; bgpPeeringAddress = '10.0.0.30'; peerWeight = 0 } natRules = @(); customDnsServers = @('10.0.0.10'); vpnGatewayGeneration = 'Generation1' }) # VPN Connection $script:MockResources += New-MockNetResource -Id '/net/conn1' -Name 'conn-s2s-onprem' ` -Type 'microsoft.network/connections' -Props ([PSCustomObject]@{ connectionType = 'IPsec'; connectionStatus = 'Connected' virtualNetworkGateway1 = [PSCustomObject]@{ id = '/net/vpngw1' } localNetworkGateway2 = [PSCustomObject]@{ id = '/net/lng1' } sharedKeyPresent = $true ingressBytesTransferred = 1048576; egressBytesTransferred = 2097152 ipsecPolicies = @() trafficSelectorPolicies = @() dpdTimeoutSeconds = 45 usePolicyBasedTrafficSelectors = $false provisioningState = 'Succeeded' }) # Load Balancer $script:MockResources += New-MockNetResource -Id '/net/lb1' -Name 'lb-web' ` -Type 'microsoft.network/loadbalancers' -Props ([PSCustomObject]@{ sku = [PSCustomObject]@{ name = 'Standard'; tier = 'Regional' } frontendIPConfigurations = @(@{ name = 'frontend1'; properties = [PSCustomObject]@{ privateIPAddress = $null; publicIPAddress = [PSCustomObject]@{id='/pip/pip2'} } }) backendAddressPools = @(@{ name = 'pool1' }) loadBalancingRules = @(@{ name = 'rule-http'; properties = [PSCustomObject]@{ protocol = 'Tcp'; frontendPort = 80; backendPort = 80 } }) probes = @(@{ name = 'probe-http'; properties = [PSCustomObject]@{ protocol = 'Http'; port = 80 } }) provisioningState = 'Succeeded' }) # Application Gateway $script:MockResources += New-MockNetResource -Id '/net/appgw1' -Name 'appgw-prod' ` -Type 'microsoft.network/applicationgateways' -Props ([PSCustomObject]@{ sku = [PSCustomObject]@{ name = 'Standard_v2'; tier = 'Standard_v2'; capacity = 2 } operationalState = 'Running'; provisioningState = 'Succeeded' gatewayIPConfigurations = @(@{name='gwip1';properties=[PSCustomObject]@{subnet=[PSCustomObject]@{id='/vnet/vnet1/subnets/gwsubnet'}}}) backendAddressPools = @(@{ name = 'pool1'; properties = [PSCustomObject]@{backendAddresses=@()} }) httpListeners = @(@{ name = 'listener-http'; properties = [PSCustomObject]@{ protocol='Http'; frontendPort=[PSCustomObject]@{id='/port/80'} } }) requestRoutingRules = @() }) # NSG $script:MockResources += New-MockNetResource -Id '/net/nsg1' -Name 'nsg-web' ` -Type 'microsoft.network/networksecuritygroups' -Props ([PSCustomObject]@{ securityRules = @( [PSCustomObject]@{ name = 'allow-http'; properties = [PSCustomObject]@{ priority = 100; direction = 'Inbound'; access = 'Allow'; protocol = 'Tcp'; sourcePortRange = '*'; destinationPortRange = '80'; sourceAddressPrefix = '*'; destinationAddressPrefix = '*'; provisioningState = 'Succeeded' } } ) defaultSecurityRules = @() networkInterfaces = @() subnets = @([PSCustomObject]@{id='/vnet/vnet1/subnets/default'}) provisioningState = 'Succeeded' }) # Public IP $script:MockResources += New-MockNetResource -Id '/net/pip1' -Name 'pip-vpngw' ` -Type 'microsoft.network/publicipaddresses' -Props ([PSCustomObject]@{ sku = [PSCustomObject]@{ name = 'Standard'; tier = 'Regional' } publicIPAllocationMethod = 'Static'; ipAddress = '20.1.2.3' dnsSettings = [PSCustomObject]@{ domainNameLabel = 'vpngw-pip'; fqdn = 'vpngw-pip.eastus.cloudapp.azure.com' } provisioningState = 'Succeeded'; ipConfiguration = [PSCustomObject]@{id='/net/vpngw1/ipcfg1'} }) # Route Table $script:MockResources += New-MockNetResource -Id '/net/rt1' -Name 'rt-custom' ` -Type 'microsoft.network/routetables' -Props ([PSCustomObject]@{ routes = @( [PSCustomObject]@{ name = 'route-fw'; properties = [PSCustomObject]@{ addressPrefix = '0.0.0.0/0'; nextHopType = 'VirtualAppliance'; nextHopIpAddress = '10.0.0.4' } } ) disableBgpRoutePropagation = $true; provisioningState = 'Succeeded' subnets = @() }) # Network Interface $script:MockResources += New-MockNetResource -Id '/net/nic1' -Name 'nic-vm01' ` -Type 'microsoft.network/networkinterfaces' -Props ([PSCustomObject]@{ ipConfigurations = @(@{ name='ipconf1'; properties = [PSCustomObject]@{ subnet = [PSCustomObject]@{ id = '/vnet/vnet1/subnets/default' }; privateIPAddress = '10.0.0.5'; publicIPAddress = $null } }) enableAcceleratedNetworking = $true; enableIPForwarding = $false; networkSecurityGroup = [PSCustomObject]@{id='/net/nsg1'} virtualMachine = [PSCustomObject]@{id='/vm/vm01'}; provisioningState = 'Succeeded' }) # Private Endpoint $script:MockResources += New-MockNetResource -Id '/net/pe1' -Name 'pe-storage' ` -Type 'microsoft.network/privateendpoints' -Props ([PSCustomObject]@{ subnet = [PSCustomObject]@{ id = '/vnet/vnet1/subnets/default' } privateLinkServiceConnections = @([PSCustomObject]@{ name = 'plsc-1'; properties = [PSCustomObject]@{ privateLinkServiceId = '/sa/sa1'; groupIds = @('blob'); privateLinkServiceConnectionState = [PSCustomObject]@{status='Approved';description=''} } }) networkInterfaces = @([PSCustomObject]@{id='/nic/nic-pe1'}) provisioningState = 'Succeeded' }) # Private DNS Zone $script:MockResources += New-MockNetResource -Id '/net/pdns1' -Name 'privatelink.blob.core.windows.net' ` -Type 'microsoft.network/privatednszones' -Props ([PSCustomObject]@{ numberOfRecordSets = 2; maxNumberOfRecordSets = 25000 numberOfVirtualNetworkLinks = 1; maxNumberOfVirtualNetworkLinks = 1000 provisioningState = 'Succeeded' }) # Azure Firewall $script:MockResources += New-MockNetResource -Id '/net/fw1' -Name 'fw-hub' ` -Type 'microsoft.network/azurefirewalls' -Props ([PSCustomObject]@{ sku = [PSCustomObject]@{ name = 'AZFW_VNet'; tier = 'Premium' } threatIntelMode = 'Alert'; provisioningState = 'Succeeded' ipConfigurations = @(@{ name='ipconf1'; properties = [PSCustomObject]@{ privateIPAddress = '10.0.1.4'; subnet = [PSCustomObject]@{id='/vnet/hub/subnets/AzureFirewallSubnet'} } }) firewallPolicy = [PSCustomObject]@{ id = '/net/fwpolicy1' } additionalProperties = @{} }) # Bastion $script:MockResources += New-MockNetResource -Id '/net/bastion1' -Name 'bastion-hub' ` -Type 'microsoft.network/bastionhosts' -Props ([PSCustomObject]@{ ipConfigurations = @(@{ name='ipconf1'; properties = [PSCustomObject]@{ subnet = [PSCustomObject]@{id='/vnet/hub/subnets/AzureBastionSubnet'}; publicIPAddress = [PSCustomObject]@{id='/pip/pip-bas'} } }) sku = [PSCustomObject]@{ name = 'Standard' }; dnsName = 'bst-001.bastion.azure.com' scaleUnits = 2; disableCopyPaste = $false; enableFileCopy = $true; enableIpConnect = $true enableShareableLink = $false; enableTunneling = $true; provisioningState = 'Succeeded' }) # NAT Gateway $script:MockResources += New-MockNetResource -Id '/net/nat1' -Name 'nat-prod' ` -Type 'microsoft.network/natgateways' -Props ([PSCustomObject]@{ sku = [PSCustomObject]@{ name = 'Standard' }; idleTimeoutInMinutes = 4 publicIpAddresses = @([PSCustomObject]@{id='/pip/pip-nat'}); publicIpPrefixes = @() subnets = @([PSCustomObject]@{id='/vnet/vnet1/subnets/default'}) provisioningState = 'Succeeded' }) # Traffic Manager $script:MockResources += New-MockNetResource -Id '/net/tm1' -Name 'tm-global' ` -Type 'microsoft.network/trafficmanagerprofiles' -Props ([PSCustomObject]@{ profileStatus = 'Enabled'; trafficRoutingMethod = 'Performance' dnsConfig = [PSCustomObject]@{ relativeName = 'tm-global'; fqdn = 'tm-global.trafficmanager.net'; ttl = 60 } monitorConfig = [PSCustomObject]@{ protocol = 'HTTPS'; port = 443; path = '/health'; intervalInSeconds = 30 } endpoints = @(@{ name='ep-eastus'; properties = [PSCustomObject]@{ endpointStatus='Enabled'; weight=50; priority=$null } }) provisioningState = 'Succeeded' }) # Virtual WAN $script:MockResources += New-MockNetResource -Id '/net/vwan1' -Name 'vwan-prod' ` -Type 'microsoft.network/virtualwans' -Props ([PSCustomObject]@{ type = 'Standard'; allowVnetToVnetTraffic = $true; allowBranchToBranchTraffic = $true disableVpnEncryption = $false virtualHubs = @([PSCustomObject]@{id='/net/vhub1'}) vpnSites = @([PSCustomObject]@{id='/net/vpnsite1'}) provisioningState = 'Succeeded' }) # Virtual Hub (needed by VirtualWAN module) $script:MockResources += New-MockNetResource -Id '/net/vhub1' -Name 'vhub-eastus' ` -Type 'microsoft.network/virtualhubs' -Props ([PSCustomObject]@{ addressPrefix = '10.10.0.0/24'; preferredRoutingGateway = 'ExpressRoute' virtualRouterAsn = 65515; virtualRouterIps = @('10.10.0.1','10.10.0.2') provisioningState = 'Succeeded' }) # VPN Site (needed by VirtualWAN module) $script:MockResources += New-MockNetResource -Id '/net/vpnsite1' -Name 'vpnsite-branch1' ` -Type 'microsoft.network/vpnsites' -Props ([PSCustomObject]@{ deviceProperties = [PSCustomObject]@{ deviceVendor = 'Cisco'; deviceModel = 'ISR 4451'; linkSpeedInMbps = 500 } vpnSiteLinks = @([PSCustomObject]@{ properties = [PSCustomObject]@{ ipAddress = '203.0.113.1' linkProperties = [PSCustomObject]@{ linkProviderName = 'Contoso ISP'; linkSpeedInMbps = 500 } }}) addressSpace = [PSCustomObject]@{ addressPrefixes = @('192.168.1.0/24') } provisioningState = 'Succeeded' }) # ExpressRoute $script:MockResources += New-MockNetResource -Id '/net/er1' -Name 'er-prod' ` -Type 'microsoft.network/expressroutecircuits' -Props ([PSCustomObject]@{ sku = [PSCustomObject]@{ name = 'Standard_MeteredData'; tier = 'Standard'; family = 'MeteredData' } serviceProviderProperties = [PSCustomObject]@{ serviceProviderName = 'Equinix'; peeringLocation = 'Silicon Valley'; bandwidthInMbps = 1000 } circuitProvisioningState = 'Enabled'; serviceProviderProvisioningState = 'Provisioned' provisioningState = 'Succeeded' }) # Network Watcher $script:MockResources += New-MockNetResource -Id '/net/nw1' -Name 'nw-eastus' ` -Type 'microsoft.network/networkwatchers' -Props ([PSCustomObject]@{ provisioningState = 'Succeeded' }) # Front Door (classic) $script:MockResources += New-MockNetResource -Id '/net/fd1' -Name 'fd-prod' ` -Type 'microsoft.network/frontdoors' -Props ([PSCustomObject]@{ frontendEndpoints = @(@{name='fe-prod';properties=[PSCustomObject]@{hostName='fd-prod.azurefd.net';sessionAffinityEnabledState='Disabled'}}) routingRules = @(@{name='rr-default';properties=[PSCustomObject]@{enabledState='Enabled';patternsToMatch=@('/*')}}) backendPools = @(@{name='pool1'}) provisioningState = 'Succeeded'; resourceState = 'Enabled' }) # Public DNS Zone $script:MockResources += New-MockNetResource -Id '/net/dns1' -Name 'contoso.com' ` -Type 'microsoft.network/dnszones' -Props ([PSCustomObject]@{ zoneType = 'Public'; numberOfRecordSets = 15; maxNumberofRecordSets = 10000 nameServers = @('ns1-01.azure-dns.com','ns2-01.azure-dns.net') }) } AfterAll { if (Test-Path $script:TempDir) { Remove-Item $script:TempDir -Recurse -Force } } # =================================================================== # TESTS # =================================================================== Describe 'Networking Module Files Exist' { It 'Networking module folder exists' { $script:NetworkingPath | Should -Exist } It '<Name> module file exists' -ForEach $NetworkingModules { Join-Path $script:NetworkingPath $File | Should -Exist } } Describe 'Networking Module Processing Phase — <Name>' -ForEach $NetworkingModules { BeforeAll { $script:ModFile = Join-Path $script:NetworkingPath $File $script:ResType = $Type } It 'Processing returns results when matching resources are present' { $matchedResources = $script:MockResources | Where-Object { $_.TYPE -eq $script:ResType } if ($matchedResources) { $content = Get-Content -Path $script:ModFile -Raw $sb = [ScriptBlock]::Create($content) $result = Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $script:MockResources, $null, 'Processing', $null, $null, 'Light20', $null $result | Should -Not -BeNullOrEmpty } else { Set-ItResult -Skipped -Because "No mock resource of type '$script:ResType'" } } It 'Processing does not throw when given an empty resource list' { $content = Get-Content -Path $script:ModFile -Raw $sb = [ScriptBlock]::Create($content) { Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, @(), $null, 'Processing', $null, $null, 'Light20', $null } | Should -Not -Throw } } Describe 'Networking Module Reporting Phase — <Name>' -ForEach $NetworkingModules { BeforeAll { $script:ModFile = Join-Path $script:NetworkingPath $File $script:ResType = $Type $script:WsName = $Worksheet $script:XlsxFile = Join-Path $script:TempDir ("Net_{0}_{1}.xlsx" -f $Name, [System.IO.Path]::GetRandomFileName()) $matchedResources = $script:MockResources | Where-Object { $_.TYPE -eq $script:ResType } if ($matchedResources) { $content = Get-Content -Path $script:ModFile -Raw $sb = [ScriptBlock]::Create($content) $script:ProcessedData = Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $script:MockResources, $null, 'Processing', $null, $null, 'Light20', $null } else { $script:ProcessedData = $null } } It 'Reporting phase does not throw' { if ($script:ProcessedData) { $content = Get-Content -Path $script:ModFile -Raw $sb = [ScriptBlock]::Create($content) { Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $null, $null, 'Reporting', $script:XlsxFile, $script:ProcessedData, 'Light20', $null } | Should -Not -Throw } else { Set-ItResult -Skipped -Because "No mock resource of type '$script:ResType'" } } It 'Excel file is created' { if ($script:ProcessedData) { $script:XlsxFile | Should -Exist } else { Set-ItResult -Skipped -Because "No mock resource of type '$script:ResType'" } } } Describe 'VPN Gateway — Enhanced P2S and NAT fields present' { It 'VirtualNetworkGateways processing produces P2S config fields' { $modFile = Join-Path $script:NetworkingPath 'VirtualNetworkGateways.ps1' $content = Get-Content -Path $modFile -Raw $sb = [ScriptBlock]::Create($content) $result = Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $script:MockResources, $null, 'Processing', $null, $null, 'Light20', $null $result | Should -Not -BeNullOrEmpty $row = $result | Select-Object -First 1 # Validate field presence — exact key names defined in the module $row.Keys | Should -Contain 'Name' $row.Keys | Should -Contain 'Subscription' $row.Keys | Should -Contain 'Resource Group' } } Describe 'VPN Connections — Enhanced IPsec fields present' { It 'Connections processing produces Shared Key Present and Ingress/Egress fields' { $modFile = Join-Path $script:NetworkingPath 'Connections.ps1' $content = Get-Content -Path $modFile -Raw $sb = [ScriptBlock]::Create($content) $result = Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $script:MockResources, $null, 'Processing', $null, $null, 'Light20', $null $result | Should -Not -BeNullOrEmpty $row = $result | Select-Object -First 1 $row.Keys | Should -Contain 'Type' $row.Keys | Should -Contain 'Status' } } |