Skip to main content

Network Audit Scripts - SNMP for NXOS, IOS, EOS

  • June 23, 2026
  • 0 replies
  • 6 views

cariddir
Spotter
Forum|alt.badge.img+5

As part of a network initiative, I’m sharing all the scripts that I have worked on to create an audit program. These files feed are then fed into PowerBi for better visualization by engineers and mgmt.

Power Bi Display of Forward NQE Script

 

Arista Check 

/*** * @intent SNMP Validation (eos)
* @description Validates Arista EOS SNMP configs and extracts all snmp-server lines.
***/

// ====================================================================================
// SECTION 0 — Tag Functions to allow granular matching of templates to device. This is
// the minimum information I need to classify all the devices in our network
// ===================================================================================

// Type of environment
export get_list_match_from_tags(tags: Bag<String>,
expectedValues: Bag<String>) =
max(foreach v in expectedValues
where v in tags
select v);
export get_env_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["DC", "CoLo", "Branch", "Cloud", "CoWork"]);
// Which manager owns device
export get_mgr_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["Moe", "Larry", "Curly"]);
// Which region
export get_region_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["EMEA", "AMRS", "APAC", "LATM"]);
// What is the role
export get_function_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["Firewall", "LB", "Proxy", "WLC", "Router", "Switch", "Controller"]);
// Which VRF
export return_vrf_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["vrf_Mgmt-vrf", "vrf_1", "vrf_NM", "vrf_None", "vrf_management", "vrf_mgmt", "vrf_default" ]);
// Which interface for management source
export return_mgmt_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, [ "Mgmt_Lo0", "Mgmt_Ma0", "Mgmt_Gi0", "Mgmt_Ma1" ]);


// ----------------------------------------------------------------------------
// --- NQE Patterns (used for patternMatches + blockDiff) ---
// ----------------------------------------------------------------------------

snmpCommunityPattern = `snmp-server community {string}`;
snmpServerPattern = `snmp-server host {ipv4Address} version 2c {string}`;
// ----------------------------------------------------------------------------
// --- Regex Patterns ---
reSnmpServer = re`no snmp-server [^\n]*|snmp-server [^\n]*`;
reSnmpContact = re`snmp-server contact[^\n]*`;
reSnmpLocation = re`snmp-server location[^\n]*`;

// ===================================================================================
// --- 1. Functions ---
// ===================================================================================
getConfigAsString(device) =
max(foreach command in device.outputs.commands
where command.commandType == CommandType.CONFIG
select command.response);

// ===================================================================================
// --- 2. Compliance Patterns ---
// ===================================================================================
// If no matches assign "INVESTIGATE" //
Investigate = ```
Investigate
```;
// ---------------------------Loopback0-----------------------------------------
eosDiffPatternAMRS_Lo0 = ```
snmp-server contact
snmp-server location
snmp-server local-interface Loopback0
snmp-server community CommReadOnly1 ro 1502
snmp-server community CommReadOnly2 ro 1500
snmp-server community CommReadOnly3 ro 1500
snmp-server host 192.0.2.10 version 2c CommReadOnly2
snmp-server host 192.0.2.20 version 2c CommReadOnly2
snmp-server host 192.0.2.30 version 2c CommReadOnly2
snmp-server host 192.0.2.40 version 2c CommReadOnly2
snmp-server host 192.0.2.10 version 2c CommReadOnly3
snmp-server host 192.0.2.20 version 2c CommReadOnly3
snmp-server host 192.0.2.30 version 2c CommReadOnly3
snmp-server host 192.0.2.40 version 2c CommReadOnly3
snmp-server enable traps snmp
ip access-list standard 1500
ip access-list standard 1502
```;

// ---------------------------Mgmt1 vrf NM-----------------------------------------
eosDiffPatternAMRS_Ma0_vrfNM = ```
snmp-server contact
snmp-server location
snmp-server vrf NM local-interface Management1
snmp-server community CommReadOnly1 ro 1502
snmp-server community CommReadOnly2 ro 1500
snmp-server community CommReadOnly3 ro 1500
snmp-server host 192.0.2.10 vrf NM version 2c CommReadOnly2
snmp-server host 192.0.2.20 vrf NM version 2c CommReadOnly2
snmp-server host 192.0.2.30 vrf NM version 2c CommReadOnly2
snmp-server host 192.0.2.40 vrf NM version 2c CommReadOnly2
snmp-server host 192.0.2.10 vrf NM version 2c CommReadOnly3
snmp-server host 192.0.2.20 vrf NM version 2c CommReadOnly3
snmp-server host 192.0.2.30 vrf NM version 2c CommReadOnly3
snmp-server host 192.0.2.40 vrf NM version 2c CommReadOnly3
snmp-server enable traps snmp
snmp-server enable traps bgp
snmp-server vrf NM
ip access-list standard 1500
ip access-list standard 1502
```;

// ===================================================================================
// --- 3. Main Logic ---
// ===================================================================================
main =
foreach device in network.devices
where device.platform.os == OS.ARISTA_EOS
where device.name == device.system.physicalName
where "DC" in device.tagNames
let configResponse = getConfigAsString(device)
let configAsString = if isPresent(configResponse) then configResponse else ""

let region = get_region_from_tags(device.tagNames)
let deviceFunc = get_function_from_tags(device.tagNames)
let environment = get_env_from_tags(device.tagNames)
let vrf = return_vrf_from_tags(device.tagNames)
let manager = get_mgr_from_tags(device.tagNames)
let mgmtSource = return_mgmt_from_tags(device.tagNames)
let ip = device.snapshotInfo.collectionIp

// STEP 3a: match compliance template — each branch returns {block: <template>, name: "<templateName>"}
let selected =
if environment == "DC" && mgmtSource == "Mgmt_Lo0" && vrf == "vrf_None" then {block: eosDiffPatternAMRS_Lo0, name: "eosDiffPatternAMRS_Lo0"}
else if environment == "DC" && mgmtSource == "Mgmt_Ma1" && vrf == "vrf_NM" then {block: eosDiffPatternAMRS_Ma0_vrfNM, name: "eosDiffPatternAMRS_Ma0_vrfNM"}
// add more conditions if necessary
// final else statement if no matches
else {block: Investigate, name: "Investigate"}

let eosDiffPattern = selected.block
let patternName = selected.name// STEP 3.4: Build valid lines from the selected template
let patternStr = replace(toString(eosDiffPattern), "```", "")
let patternLines = (foreach r in regexMatches(patternStr, reSnmpServer) select r.string)

let deviceContactLines = (foreach r in regexMatches(configAsString, reSnmpContact) select r.string)
let deviceLocationLines = (foreach r in regexMatches(configAsString, reSnmpLocation) select r.string)

let validLines =
(foreach line in patternLines where line != "snmp-server contact" && line != "snmp-server location" select line) + deviceContactLines + deviceLocationLines

// STEP 3b: Calculate diffs
let blockDiffResult = blockDiff(device.files.config, eosDiffPattern)

// STEP 3c: Collect ALL snmp-server lines from device via regex
let snmpList = (foreach r in regexMatches(configAsString, reSnmpServer) select r.string)
let extraLines = snmpList - validLines

// STEP 3d: Output results
select {
// First violation is standard, but I want print "Pass or Fail" so I use the next for powerBi import
// violation: blockDiffResult.diffCount > 0 || length(extraLines) > 0,
violation: if blockDiffResult.diffCount > 0 || length(extraLines) > 0 then "Fail" else "Pass",
device: device.name,
ip: ip,
os: device.platform.osVersion,
model: device.platform.model,
pattern: patternName,
missing: if blockDiffResult.diffCount == 0 then "None" else toString(blockDiffResult.blocks),
extra: if length(extraLines) == 0 then "None" else join("\n", order(extraLines)),
config: if length(snmpList) == 0 then "None" else join("\n", order(snmpList)),
region: region,
vrf: vrf,
mgmtSource: mgmtSource,
environment: environment,
function: deviceFunc,
manager: manager,
tags: device.tagNames,
};

export eos_snmp_compliance = main();

main()

IOS-XE Check

/*** * @intent SNMP Validation (IOS-XE)
* @description Validates Cisco IOX-XE SNMP configs and extracts all snmp-server lines.
***/

// ====================================================================================
// SECTION 0 — Tag Functions to allow granular matching of templates to device. This is
// the minimum information I need to classify all the devices in our network
// ===================================================================================

// Type of environment
export get_list_match_from_tags(tags: Bag<String>,
expectedValues: Bag<String>) =
max(foreach v in expectedValues
where v in tags
select v);
export get_env_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["DC", "CoLo", "Branch", "Cloud", "CoWork"]);
// Which manager owns device
export get_mgr_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["Moe", "Larry", "Curly"]);
// Which region
export get_region_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["EMEA", "AMRS", "APAC", "LATM"]);
// What is the role
export get_function_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["Firewall", "LB", "Proxy", "WLC", "Router", "Switch", "Controller"]);
// Which VRF
export return_vrf_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["vrf_Mgmt-vrf", "vrf_1", "vrf_NM", "vrf_None", "vrf_management", "vrf_mgmt", "vrf_default" ]);
// Which interface for management source
export return_mgmt_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, [ "Mgmt_Lo0", "Mgmt_Ma0", "Mgmt_Gi0", "Mgmt_Ma1" ]);


// ------------------------------------------------------------------//
// RegexPatterns — regex for pattern extraction
// ------------------------------------------------------------------//

snmpCommunityPattern = `snmp-server community {string}`;
snmpServerPattern = `snmp-server host {ipv4Address} version 2c {string}`;
snmpServerVrfPattern = `snmp-server host {ipv4Address} vrf {string} version 2c {string}`;
reTrapSource = re`snmp-server trap-source\s+\S+`;
reLocation = re`snmp-server location\s+.+`;
reContact = re`snmp-server contact\s+.+`;
// ------------------------------------------------------------------//
// --- 1. Helper Functions ---
// ------------------------------------------------------------------//

getConfigAsString(device) =
max(foreach command in device.outputs.commands
where command.commandType == CommandType.CONFIG
select command.response);
// ------------------------------------------------------------------//
// --- 2. Compliance Patterns ---
// ------------------------------------------------------------------//

IosDiffPatternDefault =
```
Investigate
```;
// these are pulled from Ryders GitHub Reposit
IosDiffPatternAmrsLan = blockPattern(network.externalSources.forwardbranchconfigs.snmpAmrsLan);
IosDiffPatternAmrsSdwan = blockPattern(network.externalSources.forwardbranchconfigs.snmpAmrsSdwan);
// ------------------ AMRS DC ---------------------//
AmrsDC_Lo0_vNone = ```
snmp-server contact
snmp-server location
snmp-server local-interface Loopback0
snmp-server community CommReadOnly1 ro 1502
snmp-server community CommReadOnly2 ro 1500
snmp-server community CommReadOnly3 ro 1500
snmp-server host 192.0.2.10 version 2c CommReadOnly1
snmp-server host 192.0.2.20 version 2c CommReadOnly1
snmp-server host 192.0.2.30 version 2c CommReadOnly1
snmp-server host 192.0.2.40 version 2c CommReadOnly2
snmp-server host 192.0.2.10 version 2c CommReadOnly2
snmp-server host 192.0.2.20 version 2c CommReadOnly2
snmp-server host 192.0.2.30 version 2c CommReadOnly3
snmp-server host 192.0.2.40 version 2c CommReadOnly3
snmp-server enable traps snmp
ip access-list standard 1500
ip access-list standard 1502
```;

// ------------------ AMRS DC source Gi0 vrf Mgmt-Intf ---------------------//
AmrsDC_Gi0_vMgmt_intf = ```
snmp-server community CommReadOnly2 RO 1500
snmp-server community CommReadOnly3 RO 1502
snmp-server community CommReadOnly1 RO 1500
snmp-server community CommReadOnly4 RO 1502
snmp-server trap-source GigabitEthernet0
snmp-server host 192.0.2.10 vrf Mgmt-intf version 2c CommReadOnly1
snmp-server host 192.0.2.10 vrf Mgmt-intf version 2c CommReadOnly1
snmp-server host 192.0.2.20 vrf Mgmt-intf version 2c CommReadOnly1
snmp-server host 192.0.2.30 vrf Mgmt-intf version 2c CommReadOnly1
snmp-server host 192.0.2.40 vrf Mgmt-intf version 2c CommReadOnly2
snmp-server host 192.0.2.10 vrf Mgmt-intf version 2c CommReadOnly2
snmp-server host 192.0.2.20 vrf Mgmt-intf version 2c CommReadOnly2
snmp-server host 192.0.2.30 vrf Mgmt-intf version 2c CommReadOnly3
snmp-server host 192.0.2.40 vrf Mgmt-intf version 2c CommReadOnly3
snmp-server enable traps snmp
ip access-list standard 1500
ip access-list standard 1502
```;
// ------------------ Add more patterns if you need ---------------------//

// ------------------------------------------------------------------//
// --- 3. Main Logic ---
// ------------------------------------------------------------------//

main =
foreach device in network.devices
where device.platform.os == OS.IOS_XE
where device.name == device.system.physicalName
let configResponse = getConfigAsString(device)
let configAsString = if isPresent(configResponse) then configResponse else ""
let region = get_region_from_tags(device.tagNames)
let deviceFunc = get_function_from_tags(device.tagNames)
let environment = get_env_from_tags(device.tagNames)
let vrf = return_vrf_from_tags(device.tagNames)
let manager = get_mgr_from_tags(device.tagNames)
let mgmtSource = return_mgmt_from_tags(device.tagNames)
let ip = device.snapshotInfo.collectionIp

// Each returns {block: <template>, name: "<templateName>"}
let selected =
if region == "AMRS" && mgmtSource == "Mgmt_Gi0" && vrf == "vrf_Mgmt-intf" && environment == "DC" && deviceFunc == "Router" then {block: AmrsDC_Gi0_vMgmt_intf, name: "AmrsDC_Gi0_vMgmt_intf"}
else if region == "AMRS" && mgmtSource == "Mgmt_Lo0" && vrf == "vrf_None" && environment == "CoLo" && deviceFunc == "Router" then {block: AmrsDC_Lo0_vNone, name: "AmrsDC_Lo0_vNone"}
else {block: IosDiffPatternDefault, name: "Dummy_Investigate"}
let IosDiffPattern = selected.block
let patternName = selected.name

// Get valid lines from the selected standard pattern.
let patternAsString = replace(toString(IosDiffPattern), "```", "")
let patternAsConfig = parseConfigBlocks(OS.OTHER, patternAsString)

let validLines =
(foreach patternMatch in patternMatches(patternAsConfig, snmpCommunityPattern)
select patternMatch.line.text) +
(foreach patternMatch in patternMatches(patternAsConfig, snmpServerPattern)
select patternMatch.line.text) +
(foreach patternMatch in patternMatches(patternAsConfig, snmpServerVrfPattern)
select patternMatch.line.text) +
(foreach r in regexMatches(patternAsString, reTrapSource) select r.string)

// blockDiff for missing lines
let blockDiffResult = blockDiff(device.files.config, IosDiffPattern)

// "snmp-server community
let configuredCommunityLines =
(foreach patternMatch in patternMatches(device.files.config, snmpCommunityPattern)
select patternMatch.line.text)

// standard "snmp-server host
let configuredHostLines =
(foreach patternMatch in patternMatches(device.files.config, snmpServerPattern)
select patternMatch.line.text)

// vrf-style "snmp-server host ... vrf
let configuredHostVrfLines =
(foreach patternMatch in patternMatches(device.files.config, snmpServerVrfPattern)
select patternMatch.line.text)

// trap-source, location, contact lines using regex
let configuredTrapSourceLines = (foreach r in regexMatches(configAsString, reTrapSource) select r.string)
let configuredLocationLines = (foreach r in regexMatches(configAsString, reLocation) select r.string)
let configuredContactLines = (foreach r in regexMatches(configAsString, reContact) select r.string)

// Include both host line types AND trap-source in configured + extra calculations.
let configuredLines = configuredCommunityLines + configuredHostLines + configuredHostVrfLines + configuredTrapSourceLines
let extraLines = configuredLines - validLines

// Combine all relevant SNMP lines for display
let snmpConfigList = distinct(
configuredCommunityLines +
configuredHostLines +
configuredHostVrfLines +
configuredTrapSourceLines +
configuredLocationLines +
configuredContactLines
)

select {
// violation: blockDiffResult.diffCount > 0 || length(extraLines) > 0,
violation: if blockDiffResult.diffCount > 0 || length(extraLines) > 0 then "Fail" else "Pass",
device: device.name,
OS: device.platform.os,
model: device.platform.model,
ip: ip,
pattern: patternName,
diffCount: blockDiffResult.diffCount,
missing: blockDiffResult.blocks,
extra: if length(extraLines) == 0 then "None" else join("\n", extraLines),
config: if length(snmpConfigList) == 0 then "None" else join("\n", order(snmpConfigList)),
region: region,
environment: environment,
mgmtSource: mgmtSource,
vrf: vrf,
function: deviceFunc,
manager: manager,
tags: device.tagNames,
};

export ios_snmp_compliance = main();

main()

NX-OS Check

/*** 
* @intent SNMP Validation (NX-OS)
* @description Validates Cisco NX-OS SNMP configs and extracts community/host/mib details.
***/

// ====================================================================================
// SECTION 0 — Tag Functions to allow granular matching of templates to device. This is
// the minimum information I need to classify all the devices in our network
// ===================================================================================

// Type of environment
export get_list_match_from_tags(tags: Bag<String>,
expectedValues: Bag<String>) =
max(foreach v in expectedValues
where v in tags
select v);
export get_env_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["DC", "CoLo", "Branch", "Cloud", "CoWork"]);
// Which manager owns device
export get_mgr_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["Moe", "Larry", "Curly"]);
// Which region
export get_region_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["EMEA", "AMRS", "APAC", "LATM"]);
// What is the role
export get_function_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["Firewall", "LB", "Proxy", "WLC", "Router", "Switch", "Controller"]);
// Which VRF
export return_vrf_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, ["vrf_Mgmt-vrf", "vrf_1", "vrf_NM", "vrf_None", "vrf_management", "vrf_mgmt", "vrf_default" ]);
// Which interface for management source
export return_mgmt_from_tags(tags: Bag<String>)= get_list_match_from_tags(tags, [ "Mgmt_Lo0", "Mgmt_Ma0", "Mgmt_Gi0", "Mgmt_Ma1" ]);

// ===================================================================================
// --- 1. NQE Inline Patterns ---
// ===================================================================================
// Used by patternMatches() against parseConfigBlocks() output for valid-line extraction.
// THREE patterns are needed for NX-OS SNMP host lines because a single host entry
// spans TWO config lines with different syntax:

snmpCommunityPattern = `snmp-server community {string}`;
snmpHostTrapsPattern = `snmp-server host {ipv4Address} traps version 2c {string}`;
snmpHostVrfPattern = `snmp-server host {ipv4Address} use-vrf {string}`;
// ===================================================================================
// --- 2. Regex Patterns ---
// ===================================================================================

// Matches ALL "snmp-server xxx ..." lines (both traps and use-vrf forms)
reNxosHostPattern = re`snmp-server host[^\n]*`;
reNxosCommunityPattern = re`snmp-server community[^\n]*`;
reNxosMibPattern = re`snmp-server mib[^\n]*`;
reTrapSource = re`snmp-server source-interface traps\s+\S+`;
reLocation = re`snmp-server location\s+.+`;
reContact = re`snmp-server contact\s+.+`;
reSnmpUserAdmin = re`snmp-server user admin`;
// ===================================================================================
// --- 3. Helper Functions ---
// ===================================================================================
getConfigAsString(device) =
max(foreach command in device.outputs.commands
where command.commandType == CommandType.CONFIG
select command.response);

isAciNode(device) =
CommandType.CISCO_ACI_FABRIC_VRFS in
(foreach command in device.outputs.commands
select command.commandType);

// ===================================================================================
// --- 4. Compliance Patterns ---
// ===================================================================================

// ---------------------------------------------------
// ---------------- AMRS -----------------------------
// ---------------------------------------------------

NxosPattnerAmrs_Ma0_vrfManagement = ```
snmp-server source-interface traps mgmt0
snmp-server user admin network-admin
snmp-server host 192.168.2.10 traps version 2c Community1
snmp-server host 192.168.2.10 use-vrf management
snmp-server host 192.168.2.20 traps version 2c Community1
snmp-server host 192.168.2.20 use-vrf management
snmp-server host 192.168.2.30 traps version 2c Community1
snmp-server host 192.168.2.30 use-vrf management
snmp-server host 192.168.2.40 traps version 2c Community1
snmp-server host 192.168.2.40 use-vrf management
snmp-server context default vrf management

snmp-server community Community2 group network-operator
snmp-server community Community1 group network-operator
snmp-server community Community1 group network-operator

snmp-server mib community-map Community2 context default
snmp-server mib community-map Community1 context default
snmp-server mib community-map Community1 context default

snmp-server community Community2 use-ipv4acl 1502
snmp-server community Community1 use-ipv4acl 1500
snmp-server community Community1 use-ipv4acl 1500
```;

// ---------------------------------------------------
// ---------------- LATM -----------------------------
// ---------------------------------------------------

nxosLATM_Lo0_GAN_DC = ```
snmp-server source-interface traps loopback0
snmp-server user admin network-admin auth md5

snmp-server host 192.168.2.10 traps version 2c Community1
snmp-server host 192.168.2.10 use-vrf GAN
snmp-server host 192.168.2.20 traps version 2c Community1
snmp-server host 192.168.2.20 use-vrf GAN
snmp-server host 192.168.2.30 traps version 2c Community1
snmp-server host 192.168.2.30 use-vrf GAN
snmp-server host 192.168.2.40 traps version 2c Community1
snmp-server host 192.168.2.40 use-vrf GAN
snmp-server context default vrf GAN

snmp-server community Community1 group network-operator
snmp-server community Community2 group network-operator
snmp-server community Community2 use-ipv4acl 1502
snmp-server community Community1 use-ipv4acl 1500
```;


// ---------------------------------------------------
// ---------------- EMEA -----------------------------
// ---------------------------------------------------
// vrf management mgmt0
nxosEMEA_VRFmanagement = ```
snmp-server source-interface traps mgmt0
snmp-server user admin network-admin auth md5

snmp-server host 7.128.0.1 traps version 2c Community1
snmp-server host 7.128.0.1 use-vrf management
snmp-server host 192.168.2.10 traps version 2c Community1
snmp-server host 192.168.2.10 use-vrf management
snmp-server host 192.168.2.20 traps version 2c Community1
snmp-server host 192.168.2.20 use-vrf management
snmp-server host 7.10.255.250 traps version 2c Community1
snmp-server host 7.10.255.250 use-vrf management
snmp-server host 192.168.2.30 traps version 2c Community1
snmp-server host 192.168.2.30 use-vrf management
snmp-server host 192.168.2.40 traps version 2c Community1
snmp-server host 192.168.2.40 use-vrf management
snmp-server host 7.6.255.250 traps version 2c Community1
snmp-server host 7.6.255.250 use-vrf management

snmp-server context default vrf management

snmp-server community *******: group network-admin
snmp-server community Community2 group network-operator
snmp-server community Community1 group network-operator
snmp-server community Community2 use-acl 1502
snmp-server community Community1 use-acl 1500
```;

// ---------------------------------------------------
// ---------------- APAC -----------------------------
// ---------------------------------------------------

nxosAPAC = ```
snmp-server source-interface traps mgmt0
snmp-server user admin network-admin auth md5

snmp-server user gnsindia network-admin auth md5
snmp-server user netadmin network-admin auth md5

snmp-server host 10.100.131.246 traps version 2c Community3
snmp-server host 10.100.131.246 use vrf-default
snmp-server host 192.168.2.10 traps version 2c Community1
snmp-server host 192.168.2.10 use-vrf default
snmp-server host 192.168.2.20 traps version 2c Community1
snmp-server host 192.168.2.20 use-vrf default
snmp-server host 192.168.2.30 traps version 2c Community1
snmp-server host 192.168.2.30 use-vrf default
snmp-server host 192.168.2.40 traps version 2c Community1
snmp-server host 192.168.2.40 use-vrf default

snmp-server context default vrf default

snmp-server community Community1 group network-operator
snmp-server community Community2 group network-operator
snmp-server community Community3 group network-operator
snmp-server mib community-map Community2 context default
snmp-server mib community-map Community1 context default

snmp-server community Community2 use-ipv4acl 1502
snmp-server community Community1 use-ipv4acl 1500
```;


// Dummy fallback — Identify Non-matches

nxosDummy = ```
investigate
```;
// ===================================================================================
// --- 5. Main Logic ---
// ===================================================================================
main =
foreach device in network.devices
where device.platform.os == OS.NXOS
where !isAciNode(device)
where device.name == device.system.physicalName
// ===================================================================================
// 5a: Get config as String for regex extraction

let configResponse = getConfigAsString(device)
let configAsString = if isPresent(configResponse) then configResponse else ""
// ===================================================================================
// 5b: Collect tag-based metadata
let region = get_region_from_tags(device.tagNames)
let deviceFunc = get_function_from_tags(device.tagNames)
let environment = get_env_from_tags(device.tagNames)
let vrf = return_vrf_from_tags(device.tagNames)
let manager = get_mgr_from_tags(device.tagNames)
let subDc = get_SubDc_from_tags(device.tagNames)
let mgmtSource = return_mgmt_from_tags(device.tagNames)
let auth = get_auth_from_tags(device.tagNames)
let ip = device.snapshotInfo.collectionIp
// ===================================================================================
// 5c. Each branch returns {block: <template>, name: "<templateName>"}
let selected =
// --- LATM ---
if region == "LATM" && environment == "DC" && vrf == "vrf_ADPGAN" && mgmtSource == "Mgmt_Lo0" then {block: nxosLATM_Lo0_ADPGAN_DC, name: "nxosLATM_Lo0_ADPGAN_DC"}
// --- EMEA ---
else if region == "EMEA" && environment == "DC" && vrf == "vrf_None" && mgmtSource == "Mgmt_Ma0" then {block: nxosEMEA_VRFmanagement, name: "nxosEMEA_VRFmanagement"}
// --- APAC ---
else if region == "APAC" && vrf == "vrf_None" && mgmtSource == "Mgmt_Ma0" then {block: nxosAPAC, name: "nxosAPAC"}
// --- AMRS ---
else if region == "AMRS" && vrf == "vrf_management" && mgmtSource == "Mgmt_Ma0" then {block: NxosPattnerAmrs_Ma0_vrfManagement, name: "NxosPattnerAmrs_Ma0_vrfManagement"}
// --- Default ---
else {block: nxosDummy, name: "No_Match_Investigate"}

let NxosDiffPattern = selected.block
let patternName = selected.name

// Re-run blockDiff against the tag-selected pattern
let blockDiffResult = blockDiff(device.files.config, NxosDiffPattern)

// Parse the winning pattern for valid-line extraction
let patternAsConfig =
parseConfigBlocks(OS.OTHER, replace(toString(NxosDiffPattern), "```", ""))

let validLines =
(foreach patternMatch in patternMatches(patternAsConfig, snmpCommunityPattern)
select patternMatch.line.text) +
(foreach patternMatch in patternMatches(patternAsConfig, snmpHostTrapsPattern)
select patternMatch.line.text) +
(foreach patternMatch in patternMatches(patternAsConfig, snmpHostVrfPattern)
select patternMatch.line.text)

// 5d: Collect actual SNMP lines from the device using regex
let hostList =
(foreach r in regexMatches(configAsString, reNxosHostPattern)
select r.string)

let communityList = (foreach r in regexMatches(configAsString, reNxosCommunityPattern) select r.string)
let mibList = (foreach r in regexMatches(configAsString, reNxosMibPattern) select r.string)
let trapSourceList = (foreach r in regexMatches(configAsString, reTrapSource) select r.string)
let locationList = (foreach r in regexMatches(configAsString, reLocation) select r.string)
let contactList = (foreach r in regexMatches(configAsString, reContact) select r.string)
let userAdminList = (foreach r in regexMatches(configAsString, reSnmpUserAdmin) select r.string)

// 5e: Compute extra lines
let configuredLines = hostList + communityList
let extraLines = configuredLines - validLines

// 5f: Combine all relevant SNMP lines for display
let snmpConfigList = distinct(
hostList +
communityList +
mibList +
trapSourceList +
locationList +
contactList +
userAdminList
)
// 5g - Choose data
select {
// violation: blockDiffResult.diffCount > 0 || length(extraLines) > 0,
violation: if blockDiffResult.diffCount > 0 || length(extraLines) > 0
then "Fail"
else "Pass",
device: device.name,
ip: ip,
os: device.platform.osVersion,
model: device.platform.model,
pattern: patternName,
missing: blockDiffResult.blocks,
extra: if length(extraLines) == 0 then "None" else join("\n", order(extraLines)),
config: if length(snmpConfigList) == 0
then "None"
else join("\n", order(snmpConfigList)),
region: region,
vrf: vrf,
mgmtSource: mgmtSource,
environment: environment,
SubEnv: subDc,
function: deviceFunc,
auth: auth,
manager: manager,
tags: device.tagNames
};

export nxos_snmp_compliance = main();

main()