Skip to content

Instantly share code, notes, and snippets.

@Siikakala
Last active February 23, 2018 07:48
Show Gist options
  • Save Siikakala/6f05242d6a285ccde419fb9fe753aebf to your computer and use it in GitHub Desktop.
Save Siikakala/6f05242d6a285ccde419fb9fe753aebf to your computer and use it in GitHub Desktop.
<#
.SYNOPSIS
Change production state of machine in Zenoss4
.DESCRIPTION
This script takes array of machines and sets their production state to some other. Returns current
and previous states of machines as integer
.EXAMPLE
.\zenoss_productionstate.ps1 -Computers computer1.example.com -ProductionState Maintenance
Will set production state of computer1 to maintenance
.EXAMPLE
.\zenoss_productionstate.ps1 -Computers computer1.example.com,computer2.example.com,computer3.example.com -ProductionState Test
Will set production state of computer1, computer2 and computer3 to test
.PARAMETER Computers
Array of computers. Accepts pipeline input. Mandatory.
.PARAMETER ProductionState
State, to which computers will be set to. Possible values are Pre-Production, Production, Maintenance, Test and Decommissioned
.PARAMETER username
Username for using Zenoss
.PARAMETER password
Password for user
.PARAMETER zenossBaseUrl
FQDN of the zenoss without https://, eg. zenoss.example.com
.PARAMETER protocol
Which protocol should be used, https heavily recommended.
.NOTES
Version 1.0
#>
#requires -version 4.0
[CmdletBinding()]
param(
[parameter(Mandatory=$true,ValueFromPipeline=$true)]
[ValidateNotNullOrEmpty()]
[Array]
$Computers,
[parameter(Mandatory=$true)]
[ValidateSet("Maintenance","Pre-Production","Production","Test","Decommissioned")]
[String]
$ProductionState,
$username = "changeme",
$password = "changeme",
$zenossBaseUrl = "zenoss.example.com",
$protocol = "https"
)
try{
# Initiate login to get session cookie
$login = Invoke-WebRequest -Uri "${protocol}://$zenossBaseUrl/zport/acl_users/cookieAuthHelper/login" -SessionVariable cookie
}catch [System.Net.WebException]{
Write-Debug "Login form exception"
throw (New-Object -TypeName System.Net.WebException -ArgumentList "Zenoss threw error when requesting login form:`n$($error[0])")
}
$loginForm = $login.Forms[0]
$loginForm.Fields["__ac_name"]=$username
$loginForm.Fields["__ac_password"]=$password
try{
# Do the actual logon
$logon = Invoke-WebRequest -Uri "${protocol}://$zenossBaseUrl/zport/acl_users/cookieAuthHelper/login" -WebSession $cookie -Method POST -Body $loginForm.Fields
}catch [System.Net.WebException]{
Write-Debug "Logon exception"
throw (New-Object -TypeName System.Net.WebException -ArgumentList "Zenoss threw error when logging in:`n$($error[0])")
}
# Checking if there is login form in the page anymore. This is bit ":D" way to check if login was successful but powershell parses the data anyway so why not.
if($($logon.forms.GetEnumerator()|where{$_.id -eq "loginform"}) -eq $null){
try{
# You need to know the path of machine (eg. /Server/Windows) to be able to change production state. Only way to figure out what it is to query all the machines from zenoss
$allDevices = Invoke-RestMethod -uri "${protocol}://$zenossBaseUrl/zport/dmd/device_router" -WebSession $cookie -DisableKeepAlive -Method POST -ContentType "application/json" -Body $(ConvertTo-Json @{action="DeviceRouter";method="getDevices";data=@(@{uid='/zport/dmd/Devices';params=@{};limit=$null});type="rpc";tid=1} -depth 5)
}catch [System.Net.WebException]{
Write-Debug "Querying all devices exception"
throw (New-Object -TypeName System.Net.WebException -ArgumentList "Zenoss threw error when querying all devices:`n$($error[0])")
}
# Query may fail.. Fortunately zenoss API will tell if it was successful or not
if($allDevices.result.success -eq $true){
# As the querying of all devices is the most costful thing, now we can change production state for many machines at once.
foreach($computer in $Computers){
# The computer name is value in hash table so we need to do reverse search. Powershell does this very efficiently
$com = $allDevices.result.devices.GetEnumerator()|where{$_.name -eq $computer}
# API returns full uri path to the machine as well in uid object, which is very helpful. Checking that if we actually found a machine.
if($com.uid -eq $null){
Write-Debug "Machine not found exception"
throw (New-Object -TypeName System.ArgumentNullException -ArgumentList "uid empty in zenoss data, is computer in zenoss? computer $computer, zenoss data: $com")
}
# Production state is integer internally in zenoss so doing the mapping here
$state = switch ($ProductionState){
"Decommissioned" { -1 }
"Maintenance" { 300 }
"Test" { 400 }
"Pre-Production" { 500 }
"Production" { 1000 }
default { 1000 }
}
try{
# And finally actually changing the production state.
$proceed = Invoke-WebRequest -Uri "${protocol}://$zenossBaseUrl/zport/dmd/device_router" -WebSession $cookie -DisableKeepAlive -Method POST -ContentType "application/json" -Body $(ConvertTo-Json @{action="DeviceRouter";method="setInfo";data=@(@{uid=$($com.uid);productionState=$state});type="rpc";tid=5} -Depth 5)
Write-Verbose $proceed.Content
# Had problems with collector changing to localhost, so changed API call above and if it is still problem in the future, API call below will handle it.
#$proceed2 = Invoke-WebRequest -Uri "${protocol}://$zenossBaseUrl/zport/dmd/device_router" -WebSession $cookie -DisableKeepAlive -Method POST -ContentType "application/json" -Body $(ConvertTo-Json @{action="DeviceRouter";method="setCollector";data=@(@{asynchronous=$false;collector=$($com.collector);hashcheck=$null;moveData=$false;uids=@($($com.uid));});type="rpc";tid=10} -Depth 5)
#Write-Verbose $proceed2.Content
}catch [System.Net.WebException]{
$errmessage = $Error[0].ErrorDetails.Message
$zenosserror = [regex]::match($errmessage,'(?si)View Error Details(.*)Traceback')
if($zenosserror -eq $null){
$zenosserr = $error[0]
}else{
$zenosserr = $zenosserror.value.Substring(18,$(($zenosserror.value.Length)-27))
}
Write-Debug "Changing production state exception"
throw (New-Object -TypeName System.Net.WebException -ArgumentList "Zenoss threw error when changing production state:`n$($zenosserr)")
}
$oldstate = switch ($com.productionState){
-1 { "Decommissioned" }
300 { "Maintenance" }
400 { "Test" }
500 { "Pre-Production" }
1000 { "Production" }
default { "Production" }
}
# Also returning the current and previous production states of the machine, this data can be used later, to change production state back to whatever it was.
[PSCustomObject]@{
Computer = $computer
PreviousState = $oldstate
CurrentState = $ProductionState
}
}
}else{
Write-Debug "Querying devices from zenoss was unsuccessful (but API call wasn't)"
throw (New-Object -TypeName System.Net.WebException -ArgumentList "Querying devices from zenoss was not successful")
}
}else{
Write-Debug "Bad username or password? What zenoss is doing?!"
throw (New-Object -TypeName System.Security.Authentication.AuthenticationException -ArgumentList "Bad username or password")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment