Adding a volume via swis powershell

Hoping I can get some insight on an issue I am running in to. I am using powershell and the swis module to automate several tasks in regards to creating a new node. Everything seems to work properly for me, however despite me adding a new volume (fixed disk), it doesn't automatically check that box under "List Resources"

I know I can do a full network discovery on the node, but this is extremely resource heavy and at the end of the discovery it notifies the entire dept of the change. It's a bit unnecessary and as I mentioned too demanding to just check that box. However if I deploy 20+ virtual machines and then use my script to add the new nodes into Solarwinds, I'd really like for that drive to be checked under "List Resources". The other devices (physical & virtual memory) get checked automatically so I'm not sure what's preventing the volume from being checked.

Here is the code block for how I am adding the volume

#================ Hard Drive Monitoring

#Get drive Info from the server directly
$Drives = Get-CimInstance -ComputerName $node -ClassName Win32_LogicalDisk -Property * | Where-Object { $_.VolumeSerialNumber -ne $NULL }

$VolumeIndex = 3

#Set the properties of our new volume(s) based on the information from above
foreach ($Drive in $Drives)
{
    $PhysicalDrive = @{   
        NodeID = $CheckNode
        VolumeType = "Fixed Disk"
        DeviceId = $Drive.DeviceID
        VolumeTypeID = "4"
        Icon = "FixedDisk.gif"
        NextRediscovery = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30)
        nextpoll = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30)
        VolumeIndex = [Int]$VolumeIndex
        Caption = $Drive.DeviceID + "\ Label: " + $Drive.VolumeName + $Drive.VolumeSerialNumber
        VolumeDescription = $Drive.DeviceID + "\ Label: " + $Drive.VolumeName + "Serial Number " + $Drive.VolumeSerialNumber
        FullName = $Drive.PSComputerName + "-" + $Drive.DeviceID + "\ Label: " + $Drive.VolumeName + $Drive.VolumeSerialNumber
        PollInterval="120"
        StatCollection="15"
        RediscoveryInterval="30"
    }

    #Create new object with properties from above
    $NewPhysicalDriveURI = New-swisobject $swis -EntityType "Orion.volumes" -properties $PhysicalDrive

    #Get new URI Properties
    $PhysicalDriveProps = Get-SwisObject $swis -uri $NewPhysicalDriveURI

    #Register Pollers
    $PhysicalDrivePoller = @{
        NetObject = "V:" + $PhysicalDriveProps["VolumeID"]
        NetObjectType = "V"
        NetObjectID = $PhysicalDriveProps["VolumeID"]
    }; 

    #Details
    $PhysicalDrivePoller["PollerType"] = "V.Details.WMI.Windows"; 
    $PhysicalDriveURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $PhysicalDrivePoller  

    #Statistics
    $PhysicalDrivePoller["PollerType"] = "V.Statistics.WMI.Windows";
    $PhysicalDriveURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $PhysicalDrivePoller  

    #Status
    $PhysicalDrivePoller["PollerType"] = "V.Status.WMI.Windows";
    $PhysicalDriveURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $PhysicalDrivePoller

    #Poll changes
    Invoke-SwisVerb $Swis "Orion.Nodes" PollNow @("V:" + $PhysicalDriveProps["VolumeID"])

    #Increment the volume index if we have multiple fixed drives
    $VolumeIndex = $VolumeIndex + 1
}

Parents
  • I was able to see this behavior as well with using your method to add a volume to a node, and got it working by changing the "VolumeIndex" to 1. What I don't understand is exactly what affect that may have, as there's both a "VolumeIndex" field and an "Index" field. Potentially they're the same data and just ones an older property name.

    That said, I was testing on a node with no volumes being monitored. Perhaps there's some logic around this to be required in various scenarios.

    Also you may want to look to add .ToUniversalTime() to the end of lines 17 and 18, the variables for NextPoll and NextRediscovery, as the DB will expect UTC.

    Hope this helps.

  • Thank you for replying. I tried changing that value and re-adding the volume, but unfortunately that change didn't make any difference. I'm trying to navigate and look at different values within our Solarwinds server using the Database Manager tool as well as SWQL to see if I can spot anything. So far unfortunately no luck. I'm open to any other suggestions.

    Let me ask a different question, but similar to this topic... is there a way to preconfigure a "template" that every new server build follows the same guidelines outside of some minor changes such as IP, servername, etc. If I were to add a server node manually we follow the same "configuration" rinse & repeat, so if there is a way to preconfigure the template to always select the options I have in my post above (including the volume) that's another option for me.

    Here is a copy of the changes I made

    foreach ($Drive in $Drives)
    {
        $PhysicalDriveProps = @{
            NodeID = $NodeID
            Icon = "FixedDisk.gif"
            Index = 1
            VolumeIndex = 1
            Caption = $Drive.DeviceID + "\ Label: " + $Drive.VolumeName + $Drive.VolumeSerialNumber
            VolumeType = "Fixed Disk"
            Size = $SourceVolume.Size
            Responding = $SourceVolume.Responding
            FullName = $Drive.PSComputerName + "-" + $Drive.DeviceID + "\ Label: " + $Drive.VolumeName + $Drive.VolumeSerialNumber
            VolumePercentUsed = $SourceVolume.VolumePercentUsed
            VolumeAllocationFailuresThisHour = $SourceVolume.VolumeAllocationFailuresThisHour
            VolumeDescription = $Drive.DeviceID + "\ Label: " + $Drive.VolumeName + "Serial Number " + $Drive.VolumeSerialNumber
            VolumeSpaceUsed = $SourceVolume.VolumeSpaceUsed
            VolumeAllocationFailuresToday = $SourceVolume.VolumeAllocationFailuresToday
            VolumeSpaceAvailable = $SourceVolume.VolumeSpaceAvailable
            VolumeTypeID = "4"
            DeviceId = $Drive.DeviceID
            NextRediscovery = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30).ToUniversalTime()
            nextpoll = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30).ToUniversalTime()
            PollInterval="120"
            StatCollection="15"
            RediscoveryInterval="30"
        }
    
        #Create new object with properties from above
        $NewPhysicalDriveURI = New-swisobject $swis -EntityType "Orion.volumes" -properties $PhysicalDriveProps
    
        #Get new URI Properties
        $NewPhysicalDriveProps = Get-SwisObject $swis -uri $NewPhysicalDriveURI
    
        foreach ($volPollerType in $SourceVolPollerTypes) 
        {
            $volPoller = @{
                PollerType = "$volPollerType";
                NetObject = "V:"+$NewPhysicalDriveProps.VolumeID;
                NetObjectType = "V";
                NetObjectID = $NewPhysicalDriveProps.VolumeID;
            }
    
            New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $volPoller | Out-Null
        }
    
        #Poll changes
        Invoke-SwisVerb $Swis "Orion.Nodes" PollNow @("V:" + $NewPhysicalDriveProps["VolumeID"])
    }

    Thank you!

  • Look into PSCustomObjects in PowerShell - https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_pscustomobject?view=powershell-7.3 and/or switches - https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_switch?view=powershell-7.3. You could create a PSCustomObject with all the predefined data for each, and use a switch to tell it which one to use depending on your condition.

    For the prior issue of it not showing in list resources, try changing your volumeindex to 1 and the below adjustments, it could potentially be comparing the end result of "mashed" data together, and it's not the same, so I looked at the formatting of the volumes when I added them through the UI, and this appears to match it.

    It appears to work for me now.

    Caption = $Drive.DeviceID + "\ Label:" + $Drive.VolumeName + " " + $Drive.VolumeSerialNumber.ToLower()
    VolumeDescription = $Drive.DeviceID + "\ Label:" + $Drive.VolumeName + "  Serial Number " + $Drive.VolumeSerialNumber.ToLower()
    FullName = $Drive.PSComputerName + "-" + $Drive.DeviceID + "\ Label: " + $Drive.VolumeName + $Drive.VolumeSerialNumber.ToLower()
     

    Also these properties are redundant amongst them and only need to define one of them in each:

    [Index, VolumeIndex] 

    [Description, Type, VolumeType]

  • I noticed exactly the same, most C: drives were volumeindex 3. But some were 1 and just couldn't make heads or tails of it to understand why. That's the "Magic sauce"... Stuck out tongue

  • Although speculating here   and  ... I do see some correlation between the polling method. It looks like at least in my environment SNMP nodes use VolumeIndex of 1 to start, and WMI/Agent nodes use VolumeIndex of 3 to start. Maybe that's due to it being Windows, and A: \ B: are reserved? Idk..

    Try taking a look in your environments with this SWQL:

    SELECT
         v.Node.ObjectSubType
        ,v.DeviceId
        ,v.VolumeIndex
        ,COUNT(v.VolumeID) AS [Total]
    FROM Orion.Volumes AS v
    WHERE v.VolumeDescription LIKE 'C:%'
    GROUP BY v.Node.ObjectSubType,v.DeviceId,v.VolumeIndex

  • So looking at that script you posted you just need to do whatever powershell command on the server gets you the disk's Index, but poking at my laptop i can't quite tell what commands will give that.  

  • Thanks to all of you for all these reply. I was off site today so I didn't get a chance to play with this anymore, but I will definitely look into the few things you posted above and see if I can get it working tomorrow. I really appreciate the responses, and I will post back my findings.

  •   
    Here is some additional information that may help.
    1. The nodes I am adding are WMI not SNMP. That being said, when I look at the tables for orion.volume, all of my fixed disks are an index value of 3+.
    So for example if a server has 1 drive then that c:\ drive would be indexed 3, if it has a 2nd drive (say drive D:\) that would be index 4 and so on... 

    So what I initially did was 

    $Drives = Get-CimInstance -ComputerName $node -ClassName Win32_LogicalDisk -Property * | Where-Object { $_.VolumeSerialNumber -ne $NULL }

    What this above code does is it tells me how many drives are on the source node. Then I do a loop through each drive and start with index 3 and then increment by 1 until it goes through all the drives. 

    As far as pscustomobjects go, what I tried doing is instead of prepopulating the data manually, I pull it from a node that actually has the volume listed in the "List Resources" section. For troubleshooting reasons I just populated the mandatory fields. 
     Here is what I came up with:

    #=================
    
    #Node we are creating the volume for
    $node = "Server6789"
    $nodeID = Get-SwisData $swis "SELECT NodeID FROM Orion.Nodes WHERE SysName='$node'"
    
    #Node we are pulling volume information from
    $NodeCopy = "Server6111"
    $nodeCopyID = Get-SwisData $swis "SELECT NodeID FROM Orion.Nodes WHERE SysName='$NodeCopy'"
    #Volume info for the node we're copying
    $NodeCopyVolumeInfo = Get-SwisData $swis "SELECT VolumeID,VolumeTypeID,VolumeIndex,VolumeDescription FROM Orion.volumes WHERE NodeID='$nodeCopyID' AND VolumeType='Fixed Disk'"
    #$Poller info for the volumes we're copying from the node
    $NodeCopyVolumePollers = Get-SwisData $swis "SELECT PollerType FROM Orion.Pollers WHERE NetObject=@netobject" @{ netobject='V:' + $NodeCopyVolumeInfo.VolumeID }
    
    #Populate our new Volume Info
    $PhysicalDrive = @{   
                NodeID = $nodeID
                VolumeTypeID = $NodeCopyVolumeInfo.VolumeTypeID
                VolumeIndex = $NodeCopyVolumeInfo.VolumeIndex
                VolumeDescription = $NodeCopyVolumeInfo.VolumeDescription
    }
    
    #Create the new Volume Object
    $PhysicalDriveURI = New-swisobject $swis -EntityType "Orion.volumes" -properties $PhysicalDrive
    
    #Grab properties for the new Object
    $nodeVolume = Get-SwisObject $swis $PhysicalDriveURI
    
     # Copy the pollers for the new Volume
    foreach ($NodeCopyVolumePoller in $NodeCopyVolumePollers) 
    {
        $volPoller = @{
            PollerType = "$NodeCopyVolumePoller";
            NetObject = "V:"+$nodeVolume.VolumeID;
            NetObjectType = "V";
            NetObjectID = $nodeVolume.VolumeID;
        }
        
        Write-Host "Adding poller $NodeCopyVolumePoller"
        New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $volPoller | Out-Null
    }
    
    New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $volPoller | Out-Null

    Anyway, I'm still stuck on the original issue, because I still can't get the volume to show in List Resources. I don't think changing the index from 3 to 1 would do it for me since as I mentioned these are WMI nodes and from looking at the tables all the servers with fixed drives start at index 3. 

    I also tried triggering a manual poll on my node like this:

    $indicationPropertiesXML = ([xml]"<dictionary xmlns='http://schemas.solarwinds.com/2007/08/informationservice/propertybag' />").DocumentElement
    $sourceInstancePropertiesXML = ([xml]"<dictionary xmlns='http://schemas.solarwinds.com/2007/08/informationservice/propertybag' />").DocumentElement
    
    (Invoke-SwisVerb $swis Orion.Rediscovery ReportIndication $nodeID, $($indicationPropertiesXML.InnerXml), $($sourceInstancePropertiesXML.InnerXml))

    Unfortunately this didn't help either.  

  • Did you try adjusting these variables inside your $PhysicalDriveProps variable to below?

    Caption = $Drive.DeviceID + "\ Label:" + $Drive.VolumeName + " " + $Drive.VolumeSerialNumber.ToLower()
    VolumeDescription = $Drive.DeviceID + "\ Label:" + $Drive.VolumeName + "  Serial Number " + $Drive.VolumeSerialNumber.ToLower()
    FullName = $Drive.PSComputerName + "-" + $Drive.DeviceID + "\ Label: " + $Drive.VolumeName + $Drive.VolumeSerialNumber.ToLower()

  • Wow, good call. I thought I tried that earlier, but I must have missed something, I just redid it and it worked... Unbelievable that just adding the ToLower() Method at the end of the caption, description and Fullname would make a difference, but it seems to be working properly for me now. 

    Thank you so much.

    Here is my full script in case anyone would like to see how I got this working:

    CLS
    
    <#
    
    ##### You might need to uncomment this code block on older systems
    
    if(([Net.ServicePointManager]::SecurityProtocol) -ne "Tls12")
    {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    }
    
    if(((Get-PSRepository).Registered) -ne $true)
    {
        Register-PSRepository -Default
    }
    
    #>
    
    #================= Import our Modules
    
    if((Get-Module -ListAvailable -Name "ImportExcel") -or (Get-Module -Name "ImportExcel"))
    {
        Import-Module ImportExcel
    }
    else
    {
        #Install NuGet (Prerequisite) first
    	Install-PackageProvider -Name NuGet -Scope CurrentUser -Force -Confirm:$False
    	
        Install-Module -Name ImportExcel -Scope CurrentUser -Force -Confirm:$False
    	Import-Module ImportExcel
    }
    
    if((Get-Module -ListAvailable -Name "SwisPowerShell") -or (Get-Module -Name "SwisPowerShell"))
    {
            #Import-Module SwisPowerShell
    }
    else
    {	
        Install-Module -Name SwisPowerShell -Scope CurrentUser -Force -Confirm:$False
    	Import-Module SwisPowerShell
    }
    
    #================= Global Variables
    
    $Start = Get-Date
    
    $Path = (Split-Path $script:MyInvocation.MyCommand.Path)
    $ExcelFile = (Get-ChildItem -Path "$Path\*.xlsx" -ErrorAction SilentlyContinue).FullName
    
    #================= Excel Import Stuff
    
    if($NULL -ne $ExcelFile)
    {
        $worksheet = (((New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList (New-Object -TypeName System.IO.FileStream -ArgumentList $ExcelFile,'Open','Read','ReadWrite')).Workbook).Worksheets[0]).Name
        $Servers = Import-Excel -Path $ExcelFile -WorkSheetname $worksheet -StartRow 1
    }
    else
    {
        #If there is no excel file to read from assume you're defining the server node as a 1-off
        $Servers = "Server1234"
    }
    
    #================= Connect to Solarwinds
    
    $swis = Connect-Swis -Hostname "Solarwinds" -Trusted
    
    Try
    {
        $swis.Open()
    }
    Catch 
    {
        Write-Host $_.Exception.Message
    }
    
    #================= Solarwinds Specific Variables
    
    #======== Set our Credentials for Solarwinds
    
    $wmiCredentialsName = "SVC_SolarWinds"
    $wmiCredentialID = ((Get-SwisData -SwisConnection $swis "SELECT ID, Name, Description, CredentialOwner FROM Orion.Credential WHERE Name = '$wmiCredentialsName'") | Where-Object { $_.CredentialOwner -eq "Orion"}).ID
    $varProps = $False
    #=================
    
    foreach($Server in $Servers)
    {
        #Check if Server has any properties imported from the spreadsheet or if we are inputting the name individually
        if((($Server.PSobject.Properties.Name) -notlike "Length") -AND ($NULL -ne $Server.PSobject.Properties.Name))
        {
            $node = $Server.ServerName
            $varProps = $True
        }
        else
        {
            $node = $Server
        }
    
        #================= Check if the node we want to create already exists
        
        $CheckNode = Get-SwisData $swis "SELECT NodeID FROM Orion.Nodes WHERE SysName='$node'"
    
        if($NULL -eq $CheckNode)
        {
            Write-Host "Creating a new node for $node"
    
            #If the node is part of the DMZ, append the FQDN
            if($Server.DMZ -eq $True)
            {
                $node += ".extnch.local"
            }
            
            #================= Create the new node
    
            $NewNodeprops = @{
                IPAddress = ([System.Net.Dns]::GetHostAddresses($node)).IPAddressToString
                EngineID = 4
                ObjectSubType = "WMI"
                DNS = ([System.Net.Dns]::GetHostByName($node)).HostName
                SysName = "$node"
                External = "False"
                Community = ""
                NextRediscovery = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30)
                nextpoll = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30)
                #-----------
                BufferNoMemThisHour  = "0"
                BufferNoMemToday     = "0"
                BufferSmMissThisHour = "0"
                BufferSmMissToday    = "0"
                BufferMdMissThisHour = "0"
                BufferMdMissToday    = "0"
                BufferBgMissThisHour = "0"
                BufferBgMissToday    = "0"
                BufferLgMissThisHour = "0"
                BufferLgMissToday    = "0"
                BufferHgMissThisHour = "0"
                BufferHgMissToday    = "0"
            }
    
            #Create new node object
            $NewNodeURI = New-SwisObject $swis -EntityType "Orion.Nodes" -Properties $NewNodeprops
    
            #Get new node URI Properties
            $nodeProps = Get-SwisObject $swis -Uri $NewNodeURI
    
            #Add node settings
            $nodeSettings = @{
                NodeID = $nodeProps["NodeID"]
                SettingName = "WMICredential"
                SettingValue = ($wmiCredentialID.ToString())
            }
    
            #Apply new node settings
            $newNodeSettings = New-SwisObject $swis -EntityType "Orion.NodeSettings" -Properties $nodeSettings
    
            #Register Pollers
            $NodePoller = @{
                NetObject = "N:" + $nodeProps["NodeID"]
                NetObjectType = "N"
                NetObjectID = $nodeProps["NodeID"]
            }
    
            # Status
            $NodePoller["PollerType"]="N.Status.ICMP.Native";
            $NodePollerUri = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $NodePoller
    
            # Response time
            $NodePoller["PollerType"]="N.ResponseTime.ICMP.Native";
            $NodePollerUri = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $NodePoller
    
            # Details
            $NodePoller["PollerType"]="N.Details.WMI.Vista";
            $NodePollerUri = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $NodePoller
    
            # Uptime
            $NodePoller["PollerType"]="N.Uptime.WMI.XP";
            $NodePollerUri = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $NodePoller
    
            # CPU
            $NodePoller["PollerType"]="N.Cpu.WMI.Windows";
            $NodePollerUri = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $NodePoller
    
            # Memory
            $NodePoller["PollerType"]="N.Memory.WMI.Windows";
            $NodePollerUri = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $NodePoller
    
            #Asset Inventory
            $NodePoller["PollerType"]="N.AssetInventory.Wmi.Generic";
            $NodePollerUri = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $NodePoller
    
            #================= Configure new node custom properties
    
            $CustomPropURI = $NewNodeURI + "/CustomProperties"
    
            #Read properties from the spreadsheet
            if($varProps -eq $True)
            {
                #Configure the Location
                if($Server.DataCenter -eq "DC01")
                {
                    $Location = "NCH800"
                }
                if($Server.DataCenter -eq "DC02")
                {
                    $Location = "3040 Salt Creek Data Center"
                }
    
                #Configure the Tier
                if($Server.Test -eq $true)
                {
                    $Tier = $Server.Tier + " - TEST"
                }
    
                if($Server.Test -eq $false)
                {
                    $Tier = $Server.Tier + " - PROD"
                }
            }
    
            $CustomProps = @{
                AlertGroup = "Server"
                #Apps = "Epic Environments"
                Apps = $Server.BS
                #BIA_Tier = "Tier 1 - PROD"
                BIA_Tier = $Tier
                Building = "DataCenter"
                Owner = "Server"
                Region = $Location
            }
    
            #Set the new custom props
            Set-SwisObject $swis -Uri $CustomPropURI -Properties $CustomProps
    
            #================ Set Ethernet Properties
    
            #Get Ethernet Info from the server directly
            $EthernetInfo = (Invoke-Command -ComputerName $node -ScriptBlock {Get-NetAdapter} | Where-Object {$_.InterfaceAlias -eq "Ethernet0"})
    
            #Set the properties of our new interface based on the information from above
            $newIfaceProps = @{
                NodeID = $nodeProps["NodeID"]
                InterfaceIndex = [Int]$EthernetInfo.InterfaceIndex
                InterfaceName = $EthernetInfo.ifDesc
                IfName = $EthernetInfo.IfName
                Caption = $EthernetInfo.ifDesc + " · " + $EthernetInfo.ifAlias
                FullName = $EthernetInfo.PSComputerName + " - " + $EthernetInfo.ifDesc + " · " + $EthernetInfo.ifAlias
                ObjectSubType = "WMI"
                Status = 1
                StatusLED = "Up.gif"
                Severity = 0
                CollectAvailability = 1
                DuplexMode = 0
                RediscoveryInterval = 30
                PollInterval = 60
                StatCollection = 3
                NextRediscovery = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30)
                nextpoll = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30)
                InterfaceIcon = "6.gif"
                Interfacetypename = "ethernetCsmacd"
                InterfacetypeDescription = "Ethernet"
                Interfacesubtype = 3
                InterfaceType = 6
                InterfaceAlias = $EthernetInfo.ifAlias
                Counter64 = "Y"
            }
    
            #Create new Interface object
            $newIfaceUri = New-SwisObject $swis -EntityType "Orion.NPM.Interfaces" -Properties $newIfaceProps
    
            #Get new Interface URI Properties
            $ifaceProps = Get-SwisObject $swis -Uri $newIfaceUri
    
            #Register Pollers
            $InterfacePoller = @{
                NetObject = "IW:" + $ifaceProps["InterfaceID"];
                NetObjectType = "IW";
                NetObjectID = $ifaceProps["InterfaceID"];
            }
    
            # Status
            $InterfacePoller["PollerType"] = "IW.Status.WMI.WinV62";
            $InterfacePollerURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $InterfacePoller
    
            # Interface Traffic
            $InterfacePoller["PollerType"] = "IW.StatisticsTraffic.WMI.WinV62";
            $InterfacePollerURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $InterfacePoller
    
            # Interface Errors
            $InterfacePoller["PollerType"] = "IW.StatisticsErrors.WMI.WinV62";
            $InterfacePollerURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $InterfacePoller
    
            # Rediscovery
            $InterfacePoller["PollerType"] = "IW.Rediscovery.WMI.WinV62";
            $InterfacePollerURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $InterfacePoller
    
            #Poll changes
            Invoke-SwisVerb $Swis "Orion.Nodes" PollNow @("IW:" + $ifaceProps["InterfaceID"])
    
            #================ Physical Memory Monitoring
    
            #Set the properties for our physical memory
            $PhysicalMem = @{   
                NodeID = $nodeProps["NodeID"]
                DeviceID = "NULL"
                VolumeType = "RAM"
                VolumeTypeID = "2"
                Icon = "RAM.gif"
                VolumeIndex = "1"
                NextRediscovery = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30)
                nextpoll = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30)
                Caption = "Physical Memory"
                FullName = $nodeProps["SysName"] + "-Physical Memory"
                VolumeDescription = "Physical Memory"
                PollInterval = "120"
                StatCollection = "15"
                RediscoveryInterval = "30"
            }
    
            #Create new object with properties from above
            $NewPhysicalMemURI = New-swisobject $swis -EntityType "Orion.volumes" -properties $PhysicalMem
    
            #Get new URI Properties
            $PhysicalMemProps = Get-SwisObject $swis -uri $NewPhysicalMemURI
    
            #Register Pollers
            $PhysicalMemPoller = @{
                NetObject = "V:" + $PhysicalMemProps["VolumeID"]
                NetObjectType = "V"
                NetObjectID = $PhysicalMemProps["VolumeID"]
            }; 
    
            #Details
            $PhysicalMemPoller["PollerType"] = "V.Details.WMI.Windows"; 
            $PhysicalMemURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $PhysicalMemPoller  
    
            #Statistics
            $PhysicalMemPoller["PollerType"] = "V.Statistics.WMI.Windows";
            $PhysicalMemURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $PhysicalMemPoller  
    
            #Status
            $PhysicalMemPoller["PollerType"] = "V.Status.WMI.Windows";
            $PhysicalMemURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $PhysicalMemPoller
    
            #Poll changes
            Invoke-SwisVerb $Swis "Orion.Nodes" PollNow @("V:" + $PhysicalMemProps["VolumeID"])
    
            #================ Virtual Memory Monitoring
    
            #Set the properties for our virtual memory
            $VirtuallMem = @{   
                NodeID = $nodeProps["NodeID"]
                VolumeType="Virtual Memory"
                DeviceID = "NULL"
                VolumeTypeID="3"
                Icon="VirtualMemory.gif"
                NextRediscovery = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30)
                nextpoll = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30)
                VolumeIndex="2"
                Caption="Virtual Memory"
                FullName = $nodeProps["SysName"] + "-Virtual Memory"
                VolumeDescription="Virtual Memory"
                PollInterval="120"
                StatCollection="15"
                RediscoveryInterval="30"
            }  
    
            #Create new object with properties from above
            $NewVirtualMemURI = New-swisobject $swis -EntityType "Orion.volumes" -properties $VirtuallMem
    
            #Get new URI Properties
            $VirtualMemProps = Get-SwisObject $swis -uri $NewVirtualMemURI
    
            #Register Pollers
            $VirtualMemPoller = @{
                NetObject = "V:" + $VirtualMemProps["VolumeID"]
                NetObjectType = "V"
                NetObjectID = $VirtualMemProps["VolumeID"]
            }; 
    
            #Details
            $VirtualMemPoller["PollerType"] = "V.Details.WMI.Windows"; 
            $VirtualMemURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $VirtualMemPoller  
    
            #Statistics
            $VirtualMemPoller["PollerType"] = "V.Statistics.WMI.Windows";
            $VirtualMemURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $VirtualMemPoller  
    
            #Status
            $VirtualMemPoller["PollerType"] = "V.Status.WMI.Windows";
            $VirtualMemURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $VirtualMemPoller
    
            #Poll changes
            Invoke-SwisVerb $Swis "Orion.Nodes" PollNow @("V:" + $VirtualMemProps["VolumeID"])
    
            #================ Hard Drive Monitoring
    
            #Get drive Info from the server directly
            $Drives = Get-CimInstance -ComputerName $node -ClassName Win32_LogicalDisk -Property * | Where-Object { $_.VolumeSerialNumber -ne $NULL }
            $VolumeIndex = 3
    
            #Set the properties of our new volume(s) based on the information from above
            foreach ($Drive in $Drives)
            {
                $NewPhysicalDrive = @{   
                    NodeID = $nodeProps["NodeID"]
                    VolumeType = "Fixed Disk"
                    DeviceId = $Drive.DeviceID
                    VolumeTypeID = "4"
                    Icon = "FixedDisk.gif"
                    NextRediscovery = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30).ToUniversalTime()
                    nextpoll = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30).ToUniversalTime()
                    VolumeIndex = [Int]$VolumeIndex
                    Caption = $Drive.DeviceID + "\ Label:" + $Drive.VolumeName + " " + $Drive.VolumeSerialNumber.ToLower()
                    VolumeDescription = $Drive.DeviceID + "\ Label:" + $Drive.VolumeName + "  Serial Number " + $Drive.VolumeSerialNumber.ToLower()
                    FullName = $Drive.PSComputerName + "-" + $Drive.DeviceID + "\ Label: " + $Drive.VolumeName + $Drive.VolumeSerialNumber.ToLower()
                    PollInterval = 60
    				StatCollection = 3
                    RediscoveryInterval = 30
                }
    
                #Create new object with properties from above
                $NewPhysicalDriveURI = New-swisobject $swis -EntityType "Orion.volumes" -properties $NewPhysicalDrive
    
                #Get new URI Properties
                $PhysicalDriveProps = Get-SwisObject $swis -uri $NewPhysicalDriveURI
    
                #Register Pollers
                $PhysicalDrivePoller = @{
                    NetObject = "V:" + $PhysicalDriveProps["VolumeID"]
                    NetObjectType = "V"
                    NetObjectID = $PhysicalDriveProps["VolumeID"]
                }; 
    
                #Details
                $PhysicalDrivePoller["PollerType"] = "V.Details.WMI.Windows"; 
                $PhysicalDriveURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $PhysicalDrivePoller  
    
                #Statistics
                $PhysicalDrivePoller["PollerType"] = "V.Statistics.WMI.Windows";
                $PhysicalDriveURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $PhysicalDrivePoller  
    
                #Status
                $PhysicalDrivePoller["PollerType"] = "V.Status.WMI.Windows";
                $PhysicalDriveURI = New-SwisObject $swis -EntityType "Orion.Pollers" -Properties $PhysicalDrivePoller
    
                #Poll changes
                Invoke-SwisVerb $swis "Orion.Nodes" PollNow @("V:" + $PhysicalDriveProps["VolumeID"])
    
                #Increment the volume index if we have multiple fixed drives
                $VolumeIndex = $VolumeIndex + 1
            }
    
            #================ Trigger a manual Poll on our new Node
    
            $netObjectID = $nodeProps.OrionIdPrefix + $nodeProps.NodeID
    
            Invoke-SwisVerb $Swis "Orion.Nodes" PollNow @($netObjectID)
    
            #================ Perform a node rediscovery (Refresh)
    
            $indicationPropertiesXML = ([xml]"
            <dictionary xmlns='http://schemas.solarwinds.com/2007/08/informationservice/propertybag' />
            ").DocumentElement
    
            $sourceInstancePropertiesXML = ([xml]"
            <dictionary xmlns='http://schemas.solarwinds.com/2007/08/informationservice/propertybag' />
            ").DocumentElement
    
            (Invoke-SwisVerb $swis Orion.Rediscovery ReportIndication $nodeProps["NodeID"], $($indicationPropertiesXML.InnerXml), $($sourceInstancePropertiesXML.InnerXml))
    
            #================ Enable Asset Inventory
    
            $EnableAssetInventoryXML = ([xml]"
            <ArrayOfint xmlns:i='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://schemas.microsoft.com/2003/10/Serialization/Arrays'>
                <int>$($nodeProps["NodeID"])</int>
            </ArrayOfint>
            ").DocumentElement
    
            $CheckAssetInventoryXML = (Invoke-SwisVerb $swis Orion.AssetInventory.Polling EnablePollingForNodes $EnableAssetInventoryXML)
            $CheckAssetInventoryXML
    
            #==============
    
            if($CheckAssetInventoryXML.InnerText -eq $False)
            {
                function AssetInventoryItemKeyXml([int]$NodeID) 
                {
                    return @"
                    <ArrayOfint xmlns:i='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://schemas.microsoft.com/2003/10/Serialization/Arrays'>
                        <int>$NodeID</int>
                    </ArrayOfint>
    "@
                }
                
                <# convert to xml param #>
                $itemKeyXml = AssetInventoryItemKeyXml $nodeProps["NodeID"]
                $itemKeys = ([xml]"$itemKeyXml").DocumentElement
    
                <# Enable #>
                $jobid = Invoke-SwisVerb -SwisConnection $swis -EntityName "Orion.AssetInventory.Polling" -Verb "EnablePollingForNodes" -Arguments @( $itemKeys )
                $jobId
            }
    
            Clear-Variable CheckNode, node, NewNodeprops, NewNodeURI, nodeProps, nodeSettings, newNodeSettings, NodePoller, NodePollerUri, CustomPropURI, Location, Tier, CustomProps, EthernetInfo, newIfaceProps, newIfaceUri, ifaceProps, InterfacePoller, InterfacePollerURI, PhysicalMem, PhysicalMemURI, PhysicalMemProps, PhysicalMemPoller, NewPhysicalMemURI, VirtuallMem, NewVirtualMemURI, VirtualMemProps, VirtualMemPoller, VirtualMemURI, Drives, NewPhysicalDrive, NewPhysicalDriveURI, PhysicalDriveProps, PhysicalDrivePoller, PhysicalDriveURI, netObjectID, EnableAssetInventoryXML, CheckAssetInventoryXML, itemKeyXml, itemKeys, jobid | Out-Null
        }
    }
    
    $End = Get-Date
    
    $End - $Start

  •  , give this a go. I'm seeing consistent results with it matching list resources as expected. Couple adjustments that may be useful for you as well, like checking to see if an existing volume exists with the same volumeindex and deviceid.

    $swis = Connect-Swis -Hostname "solarwinds-server" -Trusted
    
    $null = Get-SwisData -SwisConnection $swis -Query "SELECT TOP 1 e.EngineID FROM Orion.Engines AS e"
    
    # Update to a specific set of your test NodeID's
    $query = @"
    	SELECT
    		 n.Caption
    		,n.SysName
    		,n.ObjectSubType
    		,n.NodeID
    		,n.Uri
    	FROM Orion.Nodes AS n
    	WHERE n.NodeID IN ( 1, 2 )
    	AND n.Vendor IN ( 'Windows' )
    "@
    
    $selection = Get-SwisData -SwisConnection $swis -Query $query
    
    ForEach ($node in $selection) {
    
    	$nodeID = $node.NodeID
    
    	Write-Output("Reviewing " + $node.Caption + "'s volumes...")
    
    	Switch ($node.objectSubType) {
    		"SNMP" { $VolumeIndex = 1; $pollerTypeTech = "SNMP.Generic" }
    		"WMI" { $VolumeIndex = 3; $pollerTypeTech = "WMI.Windows" }
    		"Agent" { $VolumeIndex = 3; $pollerTypeTech = "WMI.Windows" }
    	}
    
    	$drives = Get-CimInstance -ComputerName $node.SysName -ClassName Win32_LogicalDisk -Property * | Where-Object { $_.VolumeSerialNumber -ne $NULL }
    
    	#Set the properties of our new volume(s) based on the information from above
    	ForEach ($drive in $drives) {
    	
    		$volQuery = @"
    		SELECT
    			 v.Caption
    			,v.VolumeIndex
    			,v.VolumeID
    			,v.Uri
    		FROM Orion.Volumes AS v
    		WHERE v.VolumeIndex = $VolumeIndex
    		AND v.NodeID = $nodeID
    "@
    
    		$existingVolume = $null
    	
    		$existingVolume = Get-SwisData -SwisConnection $swis -Query $volQuery
    		
    		If ($existingVolume) {
    		
    			Write-Output("`tVolume '" + $existingVolume.Caption + "' exists already with same VolumeIndex of " + [string] $VolumeIndex + ", ignoring.")
    			
    			#Increment the volume index if we have multiple fixed drives
    			$VolumeIndex ++
    		
    			Continue
    		
    		} Else {
    		
    			$PhysicalDrive = @{   
    			
    				NodeID = $node.NodeID
    				VolumeType = "Fixed Disk"
    				DeviceId = $drive.DeviceID
    				VolumeTypeID = 4
    				Icon = "FixedDisk.gif"
    				NextRediscovery = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30).ToUniversalTime()
    				NextPoll = (Get-Date (Get-Date -Format "MM.dd.yyy h:mm:ss tt")).AddSeconds(30).ToUniversalTime()
    				VolumeIndex = [Int] $VolumeIndex
    				Caption = $drive.DeviceID + "\ Label:" + $drive.VolumeName + " " + $drive.VolumeSerialNumber.ToLower()
    				VolumeDescription = $drive.DeviceID + "\ Label:" + $drive.VolumeName + "  Serial Number " + $drive.VolumeSerialNumber.ToLower()
    				FullName = $drive.PSComputerName + "-" + $drive.DeviceID + "\ Label: " + $drive.VolumeName + $drive.VolumeSerialNumber.ToLower()
    				PollInterval = 120
    				StatCollection = 15
    				RediscoveryInterval = 30
    				
    			}
    			
    			Write-Output("`tAdding Volume '" + $PhysicalDrive.Caption + "'...")
    
    			#Create new object with properties from above
    			$NewPhysicalDriveURI = New-SwisObject -SwisConnection $swis -EntityType "Orion.Volumes" -Properties $PhysicalDrive
    
    			#Get new URI Properties
    			$PhysicalDriveProps = Get-SwisObject -SwisConnection $swis -Uri $NewPhysicalDriveURI
    
    			#Register Pollers
    			$PhysicalDrivePoller = @{
    				NetObject = "V:" + $PhysicalDriveProps["VolumeID"]
    				NetObjectType = "V"
    				NetObjectID = $PhysicalDriveProps["VolumeID"]
    				Enabled = $true
    			}
    
    			#Details
    			$PhysicalDrivePoller["PollerType"] = "V.Details." + $pollerTypeTech
    			$PhysicalDriveURI = New-SwisObject -SwisConnection $swis -EntityType "Orion.Pollers" -Properties $PhysicalDrivePoller  
    
    			#Statistics
    			$PhysicalDrivePoller["PollerType"] = "V.Statistics." + $pollerTypeTech
    			$PhysicalDriveURI = New-SwisObject -SwisConnection $swis -EntityType "Orion.Pollers" -Properties $PhysicalDrivePoller  
    
    			#Status
    			$PhysicalDrivePoller["PollerType"] = "V.Status." + $pollerTypeTech
    			$PhysicalDriveURI = New-SwisObject -SwisConnection $swis -EntityType "Orion.Pollers" -Properties $PhysicalDrivePoller
    
    			#Poll changes
    			$null = Invoke-SwisVerb -SwisConnection $Swis -EntityName "Orion.Nodes" -Verb PollNow -Arguments @("V:" + $PhysicalDriveProps.VolumeID)
    			
    			#Increment the volume index if we have multiple fixed drives
    			$VolumeIndex ++
    			
    		}
    		
    	}
    	
    }

  • Thank you so much for this. Yes, this is definitely helpful. Using similar logic to what you have above, I am wondering if it's possible to have an additional check. For example if the volume already exists, but it doesn't equal the same (case sensitive) characters to what the Caption, VolumeDescription, and FullName should be, so it updates it so it's in the correct format so that these too will properly be listed under "List Resources".

Reply
  • Thank you so much for this. Yes, this is definitely helpful. Using similar logic to what you have above, I am wondering if it's possible to have an additional check. For example if the volume already exists, but it doesn't equal the same (case sensitive) characters to what the Caption, VolumeDescription, and FullName should be, so it updates it so it's in the correct format so that these too will properly be listed under "List Resources".

Children
No Data