This discussion has been locked. The information referenced herein may be inaccurate due to age, software updates, or external references.
You can no longer post new replies to this discussion. If you have a similar question you can start a new discussion in this forum.

how to manage and unmanage nodes via powershell

I'm trying to find a way to semi-automate the managing and unmanaging of nodes for monthly patching.  I have been trying to use the PS module, but found the documentation on the github wiki lacking in how to incorporate the commands into a powershell script. 

I found these two resources on Thwack, but they don't seem to be working

https://thwack.solarwinds.com/t5/Orion-SDK-Discussions/Mute-Alerts-in-SolarWinds-via-Powershell/m-p/296302
https://thwack.solarwinds.com/t5/Orion-SDK-Discussions/Powershell-scripts-to-automatically-unmanage-remanage-a-node/m-p/354841

My goal is to have the sys admin create a text file with the hostnames that they want to unmanaged, run the script, and the script will parse the names, find the corresponding node ID, and then unmanage it for 6 hours.  if they want to manage the modes, the script will still parse the names, find the corresponding node ID, and they take effect immediately.  I think the issue is with the swis related commands, but I didn't find enough in the documentation to explain how to do it.

Here is what I have so far:

#Silently Call SolarWinds SDK
Import-Module SwisPowerShell
<#if (!(Import-Module "SwisPowerShell" -ErrorAction SilentlyContinue))
{
Import-Module SwisPowerShell -ErrorAction SilentlyContinue
} #>
#prompt user for which option they way to select
write-host "`Which option do you want to do? n`n"
do {
write-host "M - Manage a list of servers in Solarwinds"
write-host "U - Unanage a list of servers in Solarwinds"
write-host "`n"
write-host "X - Exit"
write-host "`n"
write-host -nonewline "Type your choice and press Enter: "
$choice = read-host
write-host ""
$UorM = $choice -match '^[MmUuXx]+$'
if ( -not $UorM) {
write-host "`n"
write-host "Invalid selection" -ForegroundColor red
}
} until ( $UorM )

#write-host -nonewline "Type or paste the filename that contains the list of servers you want to set to unmanage: "
$filepath = "<folder path>list.txt"
#$Username = 'username@domainname.com'
#$UserPassword = 'Users Password'
#$creds = get-credential -Message "Please enter your credentials that you used to log onto the Solarwinds Orion Platform: "
$creds = Import-CliXml -Path "<encrypted admin creds>"
$LGcreds = $creds
$nodelist = Get-Content $filepath
#establish connection to the orion server
$swis = connect-swis -Host <OrionServerName> -Credential $LGcreds
try{
Write-Host "Verifying connection to Orion."
#verify the connection to the Orion Server is successful,
$swis.Open()
}
catch{
Write-Host $_.Exception.Message
}
$now =[DateTime ]:: Now
$later =$now.AddHours(6)
#if U is selected, then start the unmanage decision tree
if (($UorM -eq 'u') -or ($UorM -eq 'U')){

$nodelist | % { $nodeid = Get-SwisData $swis "SELECT NodeID FROM Orion.Nodes WHERE SysName LIKE '$nodename%'"
Invoke-SwisVerb $swis Orion.Nodes Unmanage @("N: $nodeid ", $now ,$later , "false")
}
}
#if M is slected, than select the manage decision tree
elseif (($UorM -eq 'm') -or ($UorM -eq 'M')){
$nodelist | % { $nodeid = Get-SwisData $swis "SELECT NodeID FROM Orion.Nodes WHERE SysName LIKE '$nodename%'"
Invoke-SwisVerb $swis Orion.Nodes Remanage @("N: $nodeid ", $now ,$later , "false")
Set-SwisObject $swis -Properties @{Remanage}
}
}
#otherwise, exit the stript
else {
break script
}

####### End of Script #############

once I get this working, I'd like to get the automated manage and unmanaged working, as we have a server (actually 3) that restart every day at 10pm, so I am hoping I can stop getting the alerts that the server is down at that time.

  • The proper syntax for the Invoke-Verb statements would be the following:

    Invoke-SwisVerb $swis Orion.Nodes Unmanage @("N:$nodeId", $now, $later, "false") (exactly how you have used it)

    Invoke-SwisVerb $swis Orion.Nodes Remanage @("N: $nodeid ") (no need for other parameters besides NodeId; also, no need for Set-SwisObject $swis -Properties @{Remanage})

    The rest of the code is pretty difficult to replicate for accurate testing. 

    Another thing that I noticed is that $nodename is not defined anywhere; if it represents the current for each iteration item in the $nodelist I think you would need to substitute it with $_ .

  • Also, you can use SWQL Studio (https://github.com/solarwinds/OrionSDK/releases) to inspect the syntax for any verb and even invoke it directly:

    ioan_bucsa_0-1606237844723.png

  • Hi Dangreenhaus,

    I got it working within my environment fine, I had to rewrite the ForEach statements a little and corrected the Remanage to just use the NodeID, but otherwise it's good to go.

    ####Start #################

    #Unmamane/remanage devices
    #dangreenhasu 2020 11 24

    #Silently Call SolarWinds SDK
    Import-Module SwisPowerShell
    <#
    if (!(Import-Module "SwisPowerShell" -ErrorAction SilentlyContinue))
              { Import-Module SwisPowerShell -ErrorAction SilentlyContinue }
    #>


    #prompt user for which option they way to select
    write-host "`Which option do you want to do? n`n"
    do {
           write-host "M - Manage a list of servers in Solarwinds"
           write-host "U - Unanage a list of servers in Solarwinds"
           write-host "`n"
           write-host "X - Exit"
           write-host "`n"
           write-host -nonewline "Type your choice and press Enter: "
           $choice = read-host
           write-host ""
           $UorM = $choice -match '^[MmUuXx]+$'
           if ( -not $UorM) {
                                      write-host "`n Invalid selection" -ForegroundColor red
                                     }
         } until ( $UorM )

    #Read hostnames from file in home folder
    $filepath = "~\list.txt"

    #Get creds the old fashioned way, correct as required
    $creds = get-credential -Message "Please enter your credentials that you used to log onto the Solarwinds Orion Platform: "
    $LGcreds = $creds

    #Read node list from file
    $nodelist = Get-Content $filepath

    #Establish connection to the orion server
    $swis = connect-swis -Host $orion -Credential $LGcreds
    try{
          Write-Host "Verifying connection to Orion."
          #verify the connection to the Orion Server is successful,
          $swis.Open()
         }
    catch {
               Write-Host $_.Exception.Message
              }

    #Now and later definitions
    $now =[DateTime ]:: Now
    $later =$now.AddHours(6)

    #if Unmanage (U/u)) is selected, then start the unmanage decision tree
    if (($UorM -eq 'u') -or ($UorM -eq 'U'))

                           {
                              Foreach ($node in $nodelist)
                                            {
                                              $nodeid = Get-SwisData $swis "SELECT NodeID FROM Orion.Nodes WHERE SysName LIKE '$node'"
                                              Invoke-SwisVerb $swis Orion.Nodes Unmanage @("N: $nodeid ", $now ,$later , "false")
                                            }
                            }

    #if Manage (M/m) is selected, than select the manage decision tree
    elseif (($UorM -eq 'm') -or ($UorM -eq 'M'))
                      { 
                        Foreach ($node in $nodelist)
                                       {
                                         $nodeid = Get-SwisData $swis "SELECT NodeID FROM Orion.Nodes WHERE SysName LIKE '$node'"
                                         Invoke-SwisVerb $swis Orion.Nodes Remanage @("N: $nodeid ")
                                       }
                      }

    #otherwise, exit the script
    else { break script }
    ####End#################

    Hope it helps,
    yaquaholic

  • thank you  for the info; I am still waiting on my security team to allow me to install the SWQL studio.  I wasn't sure how much of a benefit there would be, but it looks like it would make things easier.

  • Dude, you rock!!! I was pulling my hair out on this, and now it's working!

    thanks!

  • Here's a script I use that I've adapted to match what you're trying to do here.

    There are a few differences:

    1. Using the Connect-Swis -Trusted flag is much easier (and more secure) than having a user type their credentials into a script in plain text. If the user running the script can log into SolarWinds using their AD credentials, this will work for them.
    2. I have a nifty little "menu creator" function that I use all the time. I've included it at the top of this script for you to shamelessly steal. It'll pop a dialog box if ran in the ISE, or a regular menu selection in cli.
    3. I added in some error checking:
      1. If the "list.txt" file doesn't exist in the same location the script is ran from, the script will stop with a warning.
      2. If a sysname listed in the text file doesn't exist, the output will tell you that and continue.
      3. If a user tries to set the same status the node is currently in (ex: tries to unmanage an already unmanaged node), the script will skip that node. This helps cut down on the number of calls made to SWIS.
    4. I changed the node lookup query to WHERE sysname = '$node' instead of using a LIKE. Since there were no wildcards, = should perform faster.

    There are some additional steps that the script I use in production contains, but I wanted to keep the functionality here as close to your original script as possible. 

    Function Select-Item {
    <#
        .SYNOPSIS
            Allows the user to select simple items, returns a number to indicate the selected item.
        
        .DESCRIPTION
            Produces a list on the screen with a caption followed by a message.  
            The options are then displayed one after the other, and the user can choose one.
            In the ISE, this will pop-up a dialog box.
        
        .PARAMETER ChoiceList
            An array of available choices to present to the user.
            The first letter of each option will be used as the hotkey.
        
        .PARAMETER Caption
            First line presented to the user.
            In the ISE this will be displayed in the title bar.
        
        .PARAMETER Message
            Longer, second line presented to the user.
            In the ISE, this will be the message in the dialog box.
        
        .PARAMETER Default
            The index of the default choice in ChoiceList.
            (Array indices start at 0)
        
        .EXAMPLE
            PS C:\> Select-Item -ChoiceList @('Yes','No','Cancel') -Caption 'Choose a thing.' -Message 'Would you like to continue doing a thing?' -Default 1
                
            Choose a thing.
            Would you like to continue doing a thing?
            [Y] Yes  [N] No  [C] Cancel  [?] Help (default is "N"):
    #>
        
        [OutputType([int])]
        Param
        (
            [Parameter(Mandatory = $true,
                       ValueFromPipeline = $true)]
            [array]$ChoiceList,
            [Parameter(Mandatory = $true,
                       ValueFromPipeline = $true)]
            [string]$Caption,
            [Parameter(Mandatory = $true,
                       ValueFromPipeline = $true)]
            [string]$Message,
            [Parameter(ValueFromPipeline = $true)]
            [int]$Default = 0
        )
        
        $choiceDescription = New-Object System.Collections.ObjectModel.Collection[System.Management.Automation.Host.ChoiceDescription]
        $ChoiceList | ForEach-Object { $choiceDescription.add((New-Object "System.Management.Automation.Host.ChoiceDescription" -ArgumentList "&$($_)")) }
        $Host.UI.PromptForChoice($Caption, $Message, $choiceDescription, $Default)
    }
    
    Function New-TrustedSwisConnection {
    <#
        .SYNOPSIS
            Internal function to create a connection for all cmdlets included in this module.
        
        .DESCRIPTION
            Attempts to connect to the SolarWinds Information Service using the logged in account.
        
        .PARAMETER SwisHostname
            Hostname of the server hosting the SolarWinds Information Service to connect to.
        
        .EXAMPLE
            PS C:\> New-TrustedSwisConnection
    #>
        Param (
            [string]$SwisHostname = 'YOUR DEFAULT ORION HOSTNAME HERE'
        )
        
        $Global:SwisConnection = Connect-Swis -Hostname $SwisHostname -Trusted
        Return $Global:SwisConnection
    }
    
    ### PROMPT USER FOR ACTION TO TAKE
    $choiceParams = @{
        ChoiceList = @('Unmanage Nodes','Remanage Nodes','Cancel')
        Caption = 'SolarWinds Unmanage/Remanage Nodes'
        Message = 'Should the nodes in ~\list.txt be Unmanaged or Remanaged?'
        Default = 2
    } 
    $choiceOutput = Select-Item @choiceParams
    If ($choiceOutput -eq 2) { 
        Write-Host "User selected cancel. Exiting."
        Break
    }
    
    ### ASSIGN ARRAY OF NODES TO VARIABLE
    $listPath = '.\list.txt'
    If (Test-Path -Path $listPath) { 
        $nodeList = Get-Content -Path $listPath
        Write-Host "Found a list of nodes at $listPath. Continuing..."
    }
    Else {
        Write-Host "No node list was found at $listPath. Please run the script after creating a node list. Exiting."
        Break
    }
    
    ### CONNECT TO SWIS
    Try {
        New-TrustedSwisConnection -SwisHostname 'YOURHOSTNAMEHERE' | Out-Null
    }
    Catch {
        Write-Host "A connection could not be made to SWIS. Exiting."
        Write-Host $_.Exception.Message
    }
    
    ### DATE DEFINITIONS
    $dateNow = $(Get-Date).ToUniversalTime() | Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ"
    $dateEnd = $(Get-Date).ToUniversalTime().AddHours(6) | Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ"
    
    ### COUNTERS
    $countSuccess = $countFailure = $countSkipped = 0
    
    ### DO ALL THE THINGS
    ForEach ($node in $nodeList) {
        $nodeDetails = Get-SwisData -SwisConnection $Global:SwisConnection -Query "SELECT NodeID, Unmanaged FROM Orion.Nodes WHERE SysName = '$node'" #NO NEED TO USE A LIKE WITHOUT A WILDCARD
        If (!$nodeDetails) {
            Write-Host "No node found with Hostname $node. Skipped."
            $countFailure++
            Break
        }
        $nodeId = $nodeDetails.NodeID
        Switch ($choiceOutput) {
            ### UNMANAGE
            0 {
                If ($nodeDetails.Unmanaged) {
                    $countSkipped++
                    Write-Host "$node is already unmanaged in SolarWinds. Skipped."
                }
                Else {
                    #$swisResponse = Invoke-SwisVerb -SwisConnection $global:SwisConnection -EntityName Orion.Nodes -Verb Unmanage -Arguments @("$($entityPrefix):$($nodeID)", $startDateTime, $endDateTime, $false)
                    $swisResponse = Invoke-SwisVerb -SwisConnection $Global:SwisConnection -EntityName Orion.Nodes -Verb Unmanage -Arguments @("N:$($nodeId)", $dateNow, $dateEnd, $false)
                    If ($swisResponse.nil) {
                        $countSuccess++
                        Write-Host "$node has been unmanaged for 6 hours. Continuing..."
                    }
                    Else {
                        $countFailure++
                        Write-Host "An issue occurred unmanaging $node. Continuing..."
                    }
                }
            }
            ### REMANAGE
            1 {
                If (!($nodeDetails.Unmanaged)) {
                    $countSkipped++
                    Write-Host "$node is not unmanaged in SolarWinds. Skipped."
                }
                Else {
                    $swisResponse = Invoke-SwisVerb -SwisConnection $Global:SwisConnection -EntityName Orion.Nodes -Verb Remanage -Arguments @("N:$($nodeID)")
                    If ($swisResponse.nil) {
                        $countSuccess++
                        Write-Host "$node nas been remanaged. Continuing..."
                    }
                    Else {
                        $countFailure++
                        Write-Host "An issue occurred remanaging $node. Continuing..."
                    }
                }
            }
        }
    }
    
    ### REPORT OUTCOME
    Write-Host @"
    
    Succeeded: $countSuccess
    Failed: $countFailure
    Skipped: $countSkipped
    
    "@
    
    Write-Host "Complete. Exiting."