EDIT3: Added link to content exchange script - the most current version is kept here: Perform List Resources and Auto Import Select Values - Scripts - The SolarWinds Platform - THWACK
EDIT2: I had to update the XML Import - I forgot to verify if the interface pollers were assigned - they were not but this has been fixed
EDIT: Nevermind! I figured it out!!! hahahahahahahahahah! I now have the interfaces being added - and ONLY the ones that I wanted! Now, I have a great framework to run on a schedule anytime to keep my interfaces up to date, ensure all nodes have the relevant pollers selected and keep my volumes clean and relevant! This will pair nicely with my cleanup script for unknown volume deletion and should pair well with my interface cleanup script once I get that one created!
I have used the sample scripts in the OrionSDK github for ImportListResources.ps1 ; ImportSelectedLIstResources_CPUMemory.ps1 ; and ImportSelectedListResources_Routing.ps1 as a starting point. I then used SWQL Studio to run some ad-hoc schedule list resources jobs so I could see the raw XML in notepad++ and start figuring out the XML Tree.
I have figured out how to turn on (or off I suppose) the following categories if found for the node having List Resources ran against:
Routing
CPU and Memory
Volume Utilization (should be able to filter on volume name as well with how the volume import is done as its a two phase selection process but we are selecting all of the Volume Utilization tree with all drives)
Hardware Health
VLAN
Topology: Layer 2
Topology: Layer 3
The ONLY section that is relevant for me so far is the Interface section and is one where I am not only selecting the tree but trying to filter out interfaces that i do not want based on DisplayName value.
Any assistance with this would be AWESOME and I hope this also helps others as I have come across lots of posts on here ranging from current to the over 10 years ago all ranting/raving about not being to do this exact thing unless you built it yourself (hard and really awful) or you ran a network discovery which we all know is heavy on the system to do so. I have been staring at this for two whole work days in a row and am starting to go cross-eyed!
Once this is fully figured out I will post this up on the content exchange section.
The SCM profiles, Asset Inventory, VXLAN and anything else at a "top" level in the List Resources can be turned on and off using one of the previous sections as a template since they on a similar XML Branch in the XML File.
This is a snippet of my task from my ansible playbook that I execute in my ansible platform. It essentially just does a WINRM connection to my primary poller to then run the powershell script. Its all in memory execution and I dont have to worry about plain text showing up in my event logs unless I forget to enable no_log: true (sometimes when I dev I disable it for debugging purposes and I REALLY need to update the password on this account now that I think about it lol)
tasks:
- name: Perform List Resources and Auto Import selected values
ansible.windows.win_powershell:
script: |
[CmdletBinding()]
param (
[String]
$user,
$pw
)
import-module SwisPowershell
$swis = Connect-Swis -username $user -password $pw
$XMLBranchRoute = 'DiscoveredRouting'
$XMLLeafCPU = 'DiscoveredCpuAndMemory'
$XMLBranchCPU = 'TechnologyDiscoveryGroup'
$XMLBranchVolume = 'DiscoveredVolume'
$XMLBranchGroupVolume = 'DiscoveredVolumesGroup'
$XMLElementPollerVolume = 'Volume Utilization'
$XMLBranchHardwareHealth = 'DiscoveredHardwareHealthPoller'
$XMLElementPollerVLAN = 'DiscoveredVLANs'
$XMLElementPollerTopologyL2 = 'DiscoveredLayer2'
$XMLElementPollerTopologyL3 = 'DiscoveredLayer3'
#List of nodes to perform list resources job against. This does not include any nodes in an unreachable, unknown, down or external status at time of run.
$query = "SELECT NodeID, ObjectSubType, IPAddress, Caption, Vendor, Status, StatusDescription, URI FROM Orion.Nodes WHERE ObjectSubType != 'ICMP' AND (StatusDescription NOT LIKE '%unmanaged%' AND StatusDescription NOT LIKE '%unknown%' AND StatusDescription NOT LIKE '%unreachable%' AND StatusDescription NOT LIKE '%external%' AND StatusDescription NOT LIKE '%down%')"
$NPMNodes = Get-SwisData -swisconnection $swis $query
foreach ($node in $NPMNodes) {
"Starting List Resources job for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
#JobID for each node.
$JobID = Invoke-SwisVerb $swis Orion.Nodes ScheduleListResources @($($node.NodeID))
do
{
Start-Sleep -Seconds 5
$JobStatus = Invoke-SwisVerb $swis Orion.Nodes GetScheduledListResourcesStatus @($JobID.'#text', $($node.NodeID))
"NodeID: $($node.NodeID) - JobID: $($JobID.'#text') - Status: $($JobStatus.'#text')"
} while ($JobStatus.'#text' -ne "ReadyForImport")
$JobResults = Invoke-SwisVerb $swis Orion.Nodes GetListResourcesResult @($JobID.'#text', $($node.NodeID))
"Show Raw Job Results before making selections"
$JobResults.InnerXML
#If Routing are an option then select.
$XMLBranchElementRoute = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.TypeName.'#text' -eq $XMLBranchRoute}).Children.DiscoveryResultExportItem
if ($XMLBranchElementRoute -ne $null) {
"Routing Section"
"Import XML Results for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
foreach ($LeafRoute in $XMLBranchElementRoute)
{
$LeafRoute.IsSelected = 'true'
}
}
#If Volume are an option then select.
$XMLElementBranchVolume = $JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.DisplayName.'#text' -eq $XMLElementPollerVolume}
if ($XMLElementBranchVolume -ne $null) {
#Selects top level Volume Utilization option
"Volume Section"
"Import XML Results for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
$XMLElementBranchVolume.IsSelected = 'true'
#Selects individual children volumes under top level Volume Utilization
$XMLLeafBranchVolume = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.TypeName.'#text' -eq $XMLBranchVolume}).Children.DiscoveryResultExportItem
foreach ($LeafVolume in $XMLLeafBranchVolume)
{
$LeafVolume.IsSelected = 'true'
}
$XMLLeafGroupBranchVolume = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.TypeName.'#text' -eq $XMLBranchGroupVolume}).Children.DiscoveryResultExportItem
foreach ($LeafGroupVolume in $XMLLeafGroupBranchVolume)
{
$LeafGroupVolume.IsSelected = 'true'
}
}
#If Interfaces are an option then select.
"Interface Section"
"Import XML Results for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
#Interface section for Ethernet
$XMLElementBranchInterfaceEthernet = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.DisplayName.'#text' -like '*ethernet*'})
if ($XMLElementBranchInterfaceEthernet -ne $null) {
foreach ($LeafInterface in $XMLElementBranchInterfaceEthernet) {
$LeafInterface.IsSelected = 'true'
$LeafInterface.Children.DiscoveryResultExportItem.IsSelected = 'true'
}
$XMLLeafBranchInterfaceEthernet = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.DisplayName.'#text' -like '*ethernet*'}).Children.DiscoveryResultExportItem
foreach ($LeafInterfaceStats in $XMLLeafBranchInterfaceEthernet) {
$LeafInterfaceStats.IsSelected = 'true'
}
}
#Interface section for Vlans
$XMLElementBranchInterfaceVlan = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.DisplayName.'#text' -like '*vlan*'})
if ($XMLElementBranchInterfaceVlan -ne $null) {
foreach ($LeafInterface in $XMLElementBranchInterfaceVlan) {
$LeafInterface.IsSelected = 'true'
$LeafInterface.Children.DiscoveryResultExportItem.IsSelected = 'true'
}
$XMLLeafBranchInterfacevlan = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.DisplayName.'#text' -like '*vlan*'}).Children.DiscoveryResultExportItem
foreach ($LeafInterfaceStats in $XMLLeafBranchInterfacevlan) {
$LeafInterfaceStats.IsSelected = 'true'
}
}
#Interface section for Tunnels
$XMLElementBranchInterfaceTunnel = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.DisplayName.'#text' -like '*tunnel*'})
if ($XMLElementBranchInterfaceTunnel -ne $null) {
foreach ($LeafInterface in $XMLElementBranchInterfaceTunnel) {
$LeafInterface.IsSelected = 'true'
$LeafInterface.Children.DiscoveryResultExportItem.IsSelected = 'true'
}
$XMLLeafBranchInterfaceTunnel = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.DisplayName.'#text' -like '*tunnel*'}).Children.DiscoveryResultExportItem
foreach ($LeafInterfaceStats in $XMLLeafBranchInterfaceTunnel) {
$LeafInterfaceStats.IsSelected = 'true'
}
}
#Interface section for Loopbacks
$XMLElementBranchInterfaceLoop = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.DisplayName.'#text' -like '*loopback*'})
if ($XMLElementBranchInterfaceLoop -ne $null) {
foreach ($LeafInterface in $XMLElementBranchInterfaceLoop) {
$LeafInterface.IsSelected = 'true'
$LeafInterface.Children.DiscoveryResultExportItem.IsSelected = 'true'
}
$XMLLeafBranchInterfaceLoop = ($JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.DisplayName.'#text' -like '*tunnel*'}).Children.DiscoveryResultExportItem
foreach ($LeafInterfaceStats in $XMLLeafBranchInterfaceLoop) {
$LeafInterfaceStats.IsSelected = 'true'
}
}
#If Hardware Health Sensors are an option then select.
$XMLElementBranchHardwareHealth = $JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.TypeName.'#text' -eq $XMLBranchHardwareHealth}
if ($XMLElementBranchHardwareHealth -ne $null) {
"Hardware Health Section"
"Import XML Results for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
$XMLElementBranchHardwareHealth.IsSelected = 'true'
}
#If VLAN are an option then select.
$XMLElementBranchVLAN = $JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.TypeName.'#text' -eq $XMLElementPollerVLAN}
if ($XMLElementBranchVLAN -ne $null) {
"VLAN Section"
"Import XML Results for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
foreach ($LeafVlan in $XMLElementBranchVLAN) {
$LeafVlan.IsSelected = 'true'
}
}
#If Topology: Layer 2 are an option then select.
$XMLElementBranchTopologyL2 = $JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.TypeName.'#text' -eq $XMLElementPollerTopologyL2}
if ($XMLElementBranchTopologyL2 -ne $null) {
"Topology L2 Section"
"Import XML Results for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
foreach ($LeafTopoL2 in $XMLElementBranchTopologyL2) {
$LeafTopoL2.IsSelected = 'true'
}
}
#If Topology: Layer 3 are an option then select.
$XMLElementBranchTopologyL3 = $JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.TypeName.'#text' -eq $XMLElementPollerTopologyL3}
if ($XMLElementBranchTopologyL3 -ne $null) {
"Topology L3 Section"
"Import XML Results for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
foreach ($LeafTopoL3 in $XMLElementBranchTopologyL3) {
$LeafTopoL3.IsSelected = 'true'
}
}
#If CPU and Memory are an option then select.
$XMLElementBranchCPU = $JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.TypeName.'#text' -eq $XMLBranchCPU}
if ($XMLElementBranchCPU -ne $null) {
#Makes parent section of CPU and Memory XML to true
"CPU Memory Section"
"Import XML Results for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
$XMLElementBranchCPU.IsSelected = 'true'
}
$XMLElementLeafCPU = $JobResults.DiscoveryResultExportItem.Children.DiscoveryResultExportItem.Children.DiscoveryResultExportItem | Where-Object {$_.TypeName.'#text' -eq $XMLLeafCPU}
if ($XMLElementLeafCPU -ne $null) {
#Makes child section of CPU and Memory XML to true
"CPU Memory Section"
"Import XML Results for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
$XMLElementLeafCPU.IsSelected = 'true'
}
#Imports all selected resources after processing - does not import everything
"Import XML Results for NodeID: [$($node.NodeID)] with Name: [$($node.Caption)]"
$ImportResources = Invoke-SwisVerb $swis Orion.Nodes ImportSelectedListResourcesResult @($JobID.'#text', $($node.NodeID), $JobResults)
}
parameters:
user: "{{ hostvars[inventory_hostname].username }}"
pw: "{{ pw }}"
no_log: true
# no log set on this task to ensure username/password is not shown when debugging in Ansible/Tower.
register: list_ResourcesOutput