diff --git a/CHANGELOG.md b/CHANGELOG.md index b150337..c66a01f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `actions/checkout@v7`, and asserts offline dual-stack DrawIO parenting. ### Fixed +- **`Invoke-SnmpWalk` accepts IPv6 `TargetIP`.** Validation was IPv4/FQDN-only, + so dual-stack SNMP targets failed before the walk. IPv4 and IPv6 literals + are parsed with `[System.Net.IPAddress]::TryParse`; hostnames stay accepted. + Garbage input still fails with a clear validation error. - **`Export-NetBox` IPv6 and unknown reachability.** IPv6 identity addresses go in `primary_ip6` (v6-only leaves `primary_ip4` empty). `Reachable=$null` no longer maps to `offline`; status is left empty (NetBox has no unknown). diff --git a/NetDiagram-PS/Public/Invoke-SnmpWalk.ps1 b/NetDiagram-PS/Public/Invoke-SnmpWalk.ps1 index ec35cc8..9876c6d 100644 --- a/NetDiagram-PS/Public/Invoke-SnmpWalk.ps1 +++ b/NetDiagram-PS/Public/Invoke-SnmpWalk.ps1 @@ -16,7 +16,7 @@ function Invoke-SnmpWalk { not redacted. Treat SNMP v1/v2c community strings as low-secrecy and prefer SNMPv3 with authentication for anything sensitive. .PARAMETER TargetIP - IP address or hostname (FQDN) to query. Must not begin with '-'. + IPv4 address, IPv6 address, or hostname (FQDN) to query. Must not begin with '-'. .PARAMETER Community SNMP community string. Must not begin with '-' (argument-injection guard). .PARAMETER OID @@ -27,14 +27,18 @@ function Invoke-SnmpWalk { Timeout in seconds (default: 2) .EXAMPLE Invoke-SnmpWalk -TargetIP '10.66.1.1' -Community 'public' + .EXAMPLE + Invoke-SnmpWalk -TargetIP '2001:db8::1' -Community 'public' #> [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateScript({ if ($_ -match '^-') { throw "TargetIP must not begin with '-'." } - if ($_ -notmatch '^(?:\d{1,3}(?:\.\d{1,3}){3}|[A-Za-z0-9]([A-Za-z0-9\-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9]([A-Za-z0-9\-]{0,61}[A-Za-z0-9])?)*)$') { - throw "TargetIP '$_' is not a valid IPv4 address or hostname." + $parsed = $null + if (-not [System.Net.IPAddress]::TryParse($_, [ref]$parsed) -and + $_ -notmatch '^[A-Za-z0-9]([A-Za-z0-9\-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9]([A-Za-z0-9\-]{0,61}[A-Za-z0-9])?)*$') { + throw "TargetIP '$_' is not a valid IP address or hostname." } $true })] diff --git a/tests/NetDiagram.Tests.ps1 b/tests/NetDiagram.Tests.ps1 index 413b936..f94cda5 100644 --- a/tests/NetDiagram.Tests.ps1 +++ b/tests/NetDiagram.Tests.ps1 @@ -1419,6 +1419,23 @@ Describe 'Invoke-SnmpWalk parameter validation' { { Invoke-SnmpWalk -TargetIP 'switch01.example.com' -Community 'public' } | Should -Throw -ExpectedMessage '*snmpwalk not found*' } + + It 'Accepts an IPv6 TargetIP without contacting SNMP' { + Mock Get-Command { $null } -ModuleName 'NetDiagram-PS' -ParameterFilter { $Name -like 'snmpwalk*' } + { Invoke-SnmpWalk -TargetIP '2001:db8::1' -Community 'public' } | + Should -Throw -ExpectedMessage '*snmpwalk not found*' + } + + It 'Accepts an IPv4 TargetIP without contacting SNMP' { + Mock Get-Command { $null } -ModuleName 'NetDiagram-PS' -ParameterFilter { $Name -like 'snmpwalk*' } + { Invoke-SnmpWalk -TargetIP '192.0.2.1' -Community 'public' } | + Should -Throw -ExpectedMessage '*snmpwalk not found*' + } + + It 'Rejects a garbage TargetIP with a clear validation error' { + { Invoke-SnmpWalk -TargetIP 'not a valid::address!' -Community 'public' } | + Should -Throw -ExpectedMessage '*not a valid IP address or hostname*' + } } Describe 'Invoke-PortScan parameter validation' {