PoShPRTG.psm1
$script:ModuleRoot = $PSScriptRoot $script:ModuleVersion = (Import-PowerShellDataFile -Path "$($script:ModuleRoot)\PoShPRTG.psd1").ModuleVersion # Detect whether at some level dotsourcing was enforced $script:doDotSource = Get-PSFConfigValue -FullName PoShPRTG.Import.DoDotSource -Fallback $false if ($PoShPRTG_dotsourcemodule) { $script:doDotSource = $true } <# Note on Resolve-Path: All paths are sent through Resolve-Path/Resolve-PSFPath in order to convert them to the correct path separator. This allows ignoring path separators throughout the import sequence, which could otherwise cause trouble depending on OS. Resolve-Path can only be used for paths that already exist, Resolve-PSFPath can accept that the last leaf my not exist. This is important when testing for paths. #> # Detect whether at some level loading individual module files, rather than the compiled module was enforced $importIndividualFiles = Get-PSFConfigValue -FullName PoShPRTG.Import.IndividualFiles -Fallback $false if ($PoShPRTG_importIndividualFiles) { $importIndividualFiles = $true } if (Test-Path (Resolve-PSFPath -Path "$($script:ModuleRoot)\..\.git" -SingleItem -NewChild)) { $importIndividualFiles = $true } if ("<was compiled>" -eq '<was not compiled>') { $importIndividualFiles = $true } function Import-ModuleFile { <# .SYNOPSIS Loads files into the module on module import. .DESCRIPTION This helper function is used during module initialization. It should always be dotsourced itself, in order to proper function. This provides a central location to react to files being imported, if later desired .PARAMETER Path The path to the file to load .EXAMPLE PS C:\> . Import-ModuleFile -File $function.FullName Imports the file stored in $function according to import policy #> [CmdletBinding()] Param ( [string] $Path ) $resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path).ProviderPath if ($doDotSource) { . $resolvedPath } else { $ExecutionContext.InvokeCommand.InvokeScript($false, ([scriptblock]::Create([io.file]::ReadAllText($resolvedPath))), $null, $null) } } #region Load individual files if ($importIndividualFiles) { # Execute Preimport actions foreach ($path in (& "$ModuleRoot\internal\scripts\preimport.ps1")) { . Import-ModuleFile -Path $path } # Import all internal functions foreach ($function in (Get-ChildItem "$ModuleRoot\internal\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore)) { . Import-ModuleFile -Path $function.FullName } # Import all public functions foreach ($function in (Get-ChildItem "$ModuleRoot\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore)) { . Import-ModuleFile -Path $function.FullName } # Execute Postimport actions foreach ($path in (& "$ModuleRoot\internal\scripts\postimport.ps1")) { . Import-ModuleFile -Path $path } # End it here, do not load compiled code below return } #endregion Load individual files #region Load compiled code <# This file loads the strings documents from the respective language folders. This allows localizing messages and errors. Load psd1 language files for each language you wish to support. Partial translations are acceptable - when missing a current language message, it will fallback to English or another available language. #> Import-PSFLocalizedString -Path "$($script:ModuleRoot)\en-us\*.psd1" -Module 'PoShPRTG' -Language 'en-US' <#PSScriptInfo .VERSION 1.0.0.4 .GUID 32a4f2d6-b021-4a38-8b6a-d76ceef2b02d .AUTHOR Jeffrey Snover .COMPANYNAME .COPYRIGHT .TAGS .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #> function Compare-ObjectProperty { <# .DESCRIPTION Determine the difference in properties between two objects. NOTE - if a property's type does not have a CompareTo() function, the property is converted to a string for the comparison .EXAMPLE $o1= @{a1=1;a2=2;b1=3;b2=4} PS C:\> $o2= @{a1=1;a2=2;b1=3;b2=5} PS C:\> Compare-ObjectProperty $o1 $o2 Property Value SideIndicator -------- ----- ------------- b2 4 <= b2 5 => .EXAMPLE $o1= @{a1=1;a2=2;b1=3;b2=4} PS C:\> $o2= @{a1=1;a2=2;b1=3;b2=5} PS C:\> Compare-ObjectProperty $o1 $o2 -PropertyFilter a* .EXAMPLE $o1= @{a1=1;a2=2;b1=3;b2=4} PS C:\> $o2= @{a1=1;a2=2;b1=3;b2=5} PS C:\> Compare-ObjectProperty $o1 $o2 -IncludeEqual Property Value SideIndicator -------- ----- ------------- a1 1 == a2 2 == b1 3 == b2 4 <= b2 5 => #> [CmdletBinding()] param( # ReferenceObject [Parameter(Mandatory = $true)] [object] ${ReferenceObject}, # DifferenceObject [Parameter(Mandatory = $true)] [object] ${DifferenceObject}, # You can specify which properties to compare using a wildcard (using the -LIKE operator) [String[]] ${PropertyFilter} = "*", # Don't include any properties that are different [switch] ${ExcludeDifferent}, # Include the properties which are equal [switch] ${IncludeEqual} ) #region Helper Routines function Convert-PropertyToHash { param([Parameter(Position = 0)]$inputObject) if ($null -eq $inputObject) { return @{} } elseif ($inputObject -is [HashTable]) { # We have to clone the hashtable because we are going to Remove Keys and if we don't # clone it, we'll modify the original object return $inputObject.clone() } else { $h = @{} foreach ($p in (Get-Member -InputObject $inputObject -MemberType Properties).Name) { $h.$p = $inputObject.$p } return $h } } #endregion $refH = Convert-PropertyToHash $ReferenceObject $diffH = Convert-PropertyToHash $DifferenceObject foreach ($filter in $PropertyFilter) { foreach ($p in $refH.keys | Where-Object { $_ -like $filter }) { if (! ($diffH.Contains($p)) -and !($ExcludeDifferent)) { New-Object PSObject -Property @{ SideIndicator = "<="; Property = $p; Value = $($refH.$p) } } else { # We convert these to strings and do a string comparison because there are all sorts of .NET # objects whose comparison functions don't yeild the expected results. if ($refH.$p -AND ($refH.$p | Get-Member -MemberType Method -Name CompareTo)) { $Different = $refH.$p -ne $diffH.$p } else { $Different = ("" + $refH.$p) -ne ("" + $diffH.$p) } if ($Different -and !($ExcludeDifferent)) { New-Object PSObject -Property @{ SideIndicator = "<="; Property = $p; Value = $($refH.$p) } New-Object PSObject -Property @{ SideIndicator = "=>"; Property = $p; Value = $($diffH.$p) } } elseif ($IncludeEqual) { New-Object PSObject -Property @{ SideIndicator = "=="; Property = $p; Value = $($refH.$p) } } $diffH.Remove($p) } } } if (-not $ExcludeDifferent) { foreach ($p in $diffH.keys | Where-Object { $_ -like $PropertyFilter }) { New-Object PSObject -Property @{ SideIndicator = "=>"; Property = $p; Value = $($diffH.$p) } } } } function Set-TypesNamesToPRTGObject { <# .Synopsis Set-TypesNamesToPRTGObject .DESCRIPTION Add module specific type names to result objects of a function. .NOTES Author: Andreas Bellstedt .EXAMPLE Set-TypesNamesToPRTGObject $PRTGObject Work on the specified object #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding(ConfirmImpact="low", SupportsShouldProcess=$false)] param( # Object to work on $PRTGObject ) begin {} process { foreach ($item in $PRTGObject) { if ($item.pstypenames[0] -eq "PRTG.Object.Compare") { $null = $item.pstypenames.Remove("PRTG.Object.Compare") } switch ($item.LocalName) { 'probenode' { if ($item.pstypenames -notcontains "PRTG.Object.Probenode") { $item.pstypenames.Insert(0, "PRTG.Object.Probenode") } } 'group' { if ($item.pstypenames -notcontains "PRTG.Object.Group") { $item.pstypenames.Insert(0, "PRTG.Object.Group") } } 'device' { if ($item.pstypenames -notcontains "PRTG.Object.Device") { $item.pstypenames.Insert(0, "PRTG.Object.Device") } } 'sensor' { if ($item.pstypenames -notcontains "PRTG.Object.Sensor") { $item.pstypenames.Insert(0, "PRTG.Object.Sensor") } } } if ($item.pstypenames -notcontains "PRTG.Object") { $item.pstypenames.Insert(1, "PRTG.Object") } if ($item.pstypenames -notcontains "PRTG") { $item.pstypenames.Insert(2, "PRTG") } $item } } end {} } function Write-Log { <# .Synopsis Write-Log / Log Logs text to the console and/or to a file. .DESCRIPTION A comprehensive helper function for structured logging. Writes one or more messages to the different available outputchannels of the powershell and to one or more logfiles. .NOTES Version: 2.4 Author: Andreas Bellstedt History: 01.07.2016 - First Version 07.08.2016 - add logging to differnt output channels and more flexibility in parameters 14.08.2016 - changing synopsis position to powershell best practices. (before funktion block) 27.01.2017 - add parameters $Type and $logscope to easy logging structur and prevent the need of global variables for (status)types 29.01.2017 - change debug output procedure for better handling .EXAMPLE Examples without logging to a file. Only console output is done. The following examples only produces output if the verbosepreference in current session is set to "continue", or the -verbose switch is specified: Write-Log -LogText "This is a Message" Write-Log "This is a Message" Log "This is a Message" "This is a Message" | Write-Log -> VERBOSE: [2016-08-08 08:08:08] [NOFILE] This is a Message "This is a Message" , "This is anonther Message" | Write-Log -LogType Info -> VERBOSE: [2016-08-08 08:08:08] [NOFILE] [INFO ] This is a Message VERBOSE: [2016-08-08 08:08:08] [NOFILE] [INFO ] This is another Message .EXAMPLE Examples without logging to a file. Only console output is done. The following examples produces output irrespective of the verbosepreference: Write-Log -LogText "This is a Message" -LogType Warning -LogScope "Function01" -Warning -> WARNING: [2016-08-08 08:08:08] [NOFILE] [WARNING] [FUNCTION01] This is a Message Write-Log -LogText "This is a Message" -LogType Error -LogScope "Function01" -Error -> Write-Log : [2016-08-07 16:13:28] [NOFILE] [ERROR ] [FUNCTION01] This is a Message + Write-Log -LogText "This is a Message" -Error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-Log Write-Log -LogText "This is a Message" -Console Write-Log -LogText "This is a Message" -Visible -> [2016-08-08 08:08:08] [NOFILE] This is a Message Write-Log -LogText "This is a Message" -Console -Warning -> WARNING: [2016-08-08 08:08:08] [NOFILE] This is a Message Write-Log -LogText "This is a Message" -Console -NoFileStatus -> [2016-08-08 08:08:08] This is a Message Write-Log -LogText "This is a Message" -Console -NoFileStatus -NoTimeStamp -> This is a Message .EXAMPLE Examples without logging to a file. Only console output is done. The following examples produces output to the debug channel: Write-Log -LogText "This is a Message" -DebugOutput -> DEBUG: [2016-08-08 08:08:08] [NOFILE] This is a Message Write-Log -LogText "This is a Message" -DebugOutput -Warning -> DEBUG: WARNING: [2016-08-08 08:08:08] [NOFILE] This is a Message .EXAMPLE Examples without logging to a file. Write-Log -LogText "This is a Message" -LogFile 'C:\Administration\Logs\Logfile.log' -> VERBOSE: [2016-08-08 08:08:08] [FILE ] This is a Message Write-Log -LogText "This is a Message" -LogFile 'C:\Administration\Logs\Logfile.log', 'C:\Administration\Logs\Logfile-Errors.log' -Warning -> WARNING: [2016-08-08 08:08:08] [FILE ] This is a Message Write-Log -LogText "This is a Message" -LogFile 'C:\Administration\Logs\Logfile.log', 'C:\Administration\Logs\Logfile-Errors.log' -Error -> Write-Log : [2016-08-08 08:08:08] [FILE ] This is a Message In Zeile:1 Zeichen:1 + Write-Log -LogText "This is a Message" -LogFile 'C:\Administration\Lo ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Write-Log #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")] [CmdletBinding( DefaultParameterSetName = 'VerboseOutput', ConfirmImpact = "Low" )] [Alias('Log')] Param( #The message to be logged [parameter( Mandatory = $true, Position = 0, ValueFromPipeline = $true )] [Alias('Text', 'Message')] [string]$LogText, #The kind of event/action what is happening while the message is logged [parameter( Mandatory = $false, Position = 1)] [Alias('Type')] [ValidateSet('Warning', 'Info', 'Query', 'Set', 'Error')] [string]$LogType, #The name of the function or the scriptpart where the log event happens [parameter( Mandatory = $false, Position = 2 )] [Alias('Scope')] [string]$LogScope, #The name of the logfile(s) where the message should be logged [parameter( Mandatory = $false )] [Alias('File')] [string[]]$LogFile, #Suppress the timestamp in the logged output [parameter( Mandatory = $false )] [switch]$NoTimeStamp, #Suppress the info, wether the logged output is written to file or only displayed in the outputchannel [parameter( Mandatory = $false )] [switch]$NoFileStatus, #Specifies that LogText is displayed as text in the debug-channel, not in the verbose-channel [parameter( Mandatory = $false, ParameterSetName = 'DebugOutput' )] [switch]$DebugOutput, #Specifies that LogText is displayed as text in the console window, not in the verbose-channel [parameter( Mandatory = $false, ParameterSetName = 'ConsoleOutput' )] [Alias('Visible')] [switch]$Console, #Specifies that LogText is displayed as (red) error message in the console window, not in the verbose-channel [parameter( Mandatory = $false, ParameterSetName = 'ErrorOutput' )] [switch]$Error, #Logs the LogText as warrning message to the console [parameter( Mandatory = $false, ParameterSetName = 'VerboseOutput' )] [parameter( Mandatory = $false, ParameterSetName = 'DebugOutput' )] [parameter( Mandatory = $false, ParameterSetName = 'ConsoleOutput' )] [switch]$Warning ) begin { switch ($LogType) { 'Warning' { $Type = '[WARNING] ' } 'Info' { $Type = '[INFO ] ' } 'Query' { $Type = '[QUERY ] ' } 'Set' { $Type = '[SET ] ' } 'Error' { $Type = '[ERROR ] ' } Default { $Type = '[INFO ] ' } } if ($logScope) { $LogScope = "[$($LogScope.ToUpper())] " } if ($NoFileStatus) { $status = '' } else { $status = "[NOFILE] " } if ($NoTimeStamp) { $logDate = '' } else { $logDate = "[$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")] " } #turn of confimation for debug actions If (($DebugPreference -eq 'Inquire') -and ($PsCmdlet.ParameterSetName -eq 'DebugOutput')) { $DebugPreferenceOrg = $DebugPreference $DebugPreference = 'Continue' } } process { if ($LogFile) { foreach ($File in $LogFile) { "$($logDate)$($Type)$($LogScope)$($LogText)" | Out-File -FilePath $File -Append } } $message = "$($logDate)$($status)$($Type)$($LogScope)$($LogText)" switch ($PsCmdlet.ParameterSetName) { 'VerboseOutput' { if ($Warning) { Write-Warning $message } else { write-verbose $message } } 'DebugOutput' { if ($Warning) { Write-Debug "WARNING: $message" } else { Write-Debug $message } } 'ConsoleOutput' { if ($Warning) { Write-Host "WARNING: $message" -ForegroundColor $Host.PrivateData.WarningForegroundColor -BackgroundColor $Host.PrivateData.WarningBackgroundColor } else { Write-Host $message } } 'ErrorOutput' { Write-error $message } } } end { $DebugPreference = $DebugPreferenceOrg Remove-Variable message, logDate, status, Type, DebugPreferenceOrg -Force -ErrorAction Ignore -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false } } function Connect-PRTGServer { <# .Synopsis Connect-PRTGServer .DESCRIPTION Connect to PRTG Server, creates global variables with connection data and the current sensor tree from PRTG Core Server. The global variables are used as default parameters in other PRTG-module cmdlets to interact with PRTG. Connect-PRTGServer needs to be run at first when starting to work. .NOTES Author: Andreas Bellstedt Created variables by the cmdlet: $script:PRTGServer $script:PRTGUser $script:PRTGPass $script:PRTGSensorTree (created through cmdlet Invoke-PRTGSensorTreeRefresh) .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE $ServerName = "PRTG.CORP.COMPANY.COM" $Credential = Get-Credential "prtgadmin" Connect-PRTGServer -Server $ServerName -protocol HTTPS -Credential $Credential #with output the connection data $connection = Connect-PRTGServer -Server $ServerName -protocol HTTPS -Credential $Credential -PassThru .EXAMPLE $ServerName = "PRTG.CORP.COMPANY.COM" $User = "prtgadmin" $Password = "SecretP@ssw0rd" Connect-PRTGServer -Server $ServerName -protocol HTTPS -User $User -PlainTextPassword $Password -Force #with output the connection data $connection = Connect-PRTGServer -Server $servername -protocol HTTPS -User $user -PlainTextPassword $pass -Force -PassThru #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [CmdletBinding( DefaultParameterSetName = 'Credential', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] [OutputType([XML])] Param( # Url for PRTG Server [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_ -match '//') { $false }else { $true } })] [String] $Server, # Specifies if the connection is done with http or https [ValidateSet("HTTP", "HTTPS")] [ValidateNotNullOrEmpty()] [String] $protocol = "HTTPS", # The credentials to login to PRTG [Parameter(Position = 1, ParameterSetName = 'Credential')] [System.Management.Automation.PSCredential] $Credential, # The user name to login to PRTG [Parameter(Position = 1, Mandatory = $true, ParameterSetName = 'PlainTextPassword')] [Parameter(Position = 1, Mandatory = $true, ParameterSetName = 'Hash')] [ValidateNotNullOrEmpty()] [String] $User, # The password to login to PRTG [Parameter(Position = 2, Mandatory = $true, ParameterSetName = 'PlainTextPassword')] [String] $PlainTextPassword, # Enforcement switch to allow plain text parameters [Parameter(ParameterSetName = 'PlainTextPassword')] [Switch] $Force, # A PRTG login hash value [Parameter(Position = 2, Mandatory = $true, ParameterSetName = 'Hash')] [ValidateNotNullOrEmpty()] [String] $Hash, # Only login. No query of sensortree object [Alias('QuickConnect', 'NoSensorTree')] [Switch] $DoNotQuerySensorTree, # Output the sensortree object after login [Switch] $PassThru ) begin {} process { switch ($protocol) { 'HTTP' { $Prefix = 'http://' Write-Log -LogText "Unsecure $($protocol) connection detected. This is a security risk. Consider switch to HTTPS! Continue..." -LogType Warning -LogScope $MyInvocation.MyCommand.Name -Warning } 'HTTPS' { $Prefix = 'https://' Write-Log -LogText "Secure $($protocol) connection. OK." -LogType Info -LogScope $MyInvocation.MyCommand.Name -DebugOutput } } switch ($PsCmdlet.ParameterSetName) { 'Credential' { if (-not $Credential) { Write-Log -LogText "No credential specified! Credential is needed..." -LogType Warning -LogScope $MyInvocation.MyCommand.Name -Warning -NoFileStatus $Credential = Get-Credential -Message "Please specify logon cedentials for PRTG" -UserName $User } if (($credential.UserName.Split('\')).count -gt 1) { $User = $credential.UserName.Split('\')[1] } else { $User = $credential.UserName } $pass = $credential.GetNetworkCredential().Password } 'PlainTextPassword' { if ($Force) { $pass = $PlainTextPassword } else { Write-Log -LogText "Plaintextpasswords without force parameter are not permitted!" -LogType Error -LogScope $MyInvocation.MyCommand.Name -Error -NoFileStatus return } } 'Hash' { $Hash = Invoke-WebRequest -Uri "$Prefix$server/api/getpasshash.htm?username=$User&password=$Pass" -Verbose:$false -Debug:$false -ErrorAction Stop | Select-Object -ExpandProperty content Remove-Variable pass -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false } } $script:PRTGServer = $Prefix + $server $script:PRTGUser = $User $script:PRTGPass = $Hash Write-Log -LogText "Connection to PRTG ($($script:PRTGServer)) as user $($script:PRTGUser)" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Console if (-not $DoNotQuerySensorTree) { Invoke-PRTGSensorTreeRefresh -Server $script:PRTGServer -User $script:PRTGUser -Pass $script:PRTGPass -Verbose:$false } if ($PassThru) { $Result = New-Object -TypeName psobject -Property @{ Server = $Prefix + $server User = $User Pass = $Hash Authentication = "&username=$User&passhash=$Hash" } $Result } } end {} } function Disconnect-PRTGServer { <# .Synopsis Disconnect-PRTGServer .DESCRIPTION Clears variables from memory: $script:PRTGServer $script:PRTGUser $script:PRTGPass .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Disconnect-PRTGServer Remove connection data, so it disconnects from PRTG Server. #> [CmdletBinding( SupportsShouldProcess = $false, ConfirmImpact = 'medium' )] Param( # Force to disconnect and suppress errors [Switch] $Force ) if ($Force) { $ErrorAction = "SilentlyContinue" } else { $ErrorAction = "Continue" } Write-Log -LogText "Removing PRTG variables from memory" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus "PRTGServer", "PRTGUser", "PRTGPass", "PRTGSensorTree" | ForEach-Object { Get-Variable $_ -Scope global -ErrorAction $ErrorAction | Remove-Variable -Scope global -Force -ErrorAction $ErrorAction -Verbose:$false -Debug:$false -WhatIf:$false } } function Get-PRTGSensorTree { <# .Synopsis Get-PRTGSensorTree .DESCRIPTION Return the current sensortree from PRTG Server .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Get-PRTGSensorTree Query the sensortree for caching prtg current object configuration. .EXAMPLE Get-PRTGSensorTree -Server "https://prtg.corp.customer.com" -User "prtgadmin" -Pass "1111111" Query the sensortree with custom credentials for caching prtg current object configuration. #> [CmdletBinding(DefaultParameterSetName = 'Default', SupportsShouldProcess = $false, ConfirmImpact = 'Low')] Param( # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript({ if ( ($_.StartsWith("http")) ) { $true } else { $false } })] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass ) $body = @{ username = $User passhash = $Pass } Write-Log -LogText "Getting PRTG SensorTree from PRTG Server $($Server)" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput [xml]$Result = Invoke-RestMethod -Uri "$Server/api/table.xml?content=sensortree" -Body $body -ErrorAction Stop -Verbose:$false $Result.pstypenames.Insert(0, "PRTG.SensorTree") $Result.pstypenames.Insert(1, "PRTG") return $Result } function Invoke-PRTGSensorTreeRefresh { <# .Synopsis Invoke-PRTGSensorTreeRefresh .DESCRIPTION Refreshes sensortree information from prtg server .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Invoke-PRTGSensorTreeRefresh Refreshes the sensortree for caching current prtg current object configuration. .EXAMPLE Invoke-PRTGSensorTreeRefresh -Server "https://prtg.corp.customer.com" -User "prtgadmin" -Pass "111111" Refreshes the sensortree with custom credentials for caching current prtg current object configuration. #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $false, ConfirmImpact = 'medium' )] Param( # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript({ if ( ($_.StartsWith("http")) ) { $true } else { $false } })] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # Output the sensor tree [Switch] $PassThru ) Write-Log -LogText "Refresh PRTG SensorTree in Memory" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $Result = Get-PRTGSensorTree -Server $Server -User $User -Pass $Pass -Verbose:$false $script:PRTGSensorTree = $Result if ($PassThru) { $Result } } function Compare-PRTGDeviceSensorsFromTemplateTAG { <# .Synopsis Compare-PRTGDeviceSensorsFromTemplateTAG .DESCRIPTION Compares all sensors on a device by all the tags on the device against a (template) object. In default all tags starting with "Template_" are used for comparing. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Compare-PRTGDeviceSensorsFromTemplateTAG -DeviceID 200 -TemplateBaseID 100 Invokes comparisan of device with ID 200 against template device with ID 100 .EXAMPLE Compare-PRTGDeviceSensorsFromTemplateTAG -DeviceID 200 -TemplateBaseID 100 -TemplateTAGNameIdentifier "MyPersonalTemplate_" Invokes comparisan of device with ID 200 against template device with ID 100 and use "MyPersonalTemplate_" as identifier for templates .EXAMPLE Get-PRTGDevice -Name "MyDevice" | Compare-PRTGDeviceSensorsFromTemplateTAG -TemplateBaseID (Get-PRTGProbe -Name "MyTemplateProbe").ObjID -IncludeEqual Invokes comparisan of "MyDevice" against all template devices beneath MyTemplateProbe #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( # ID of the object to copy [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 })] [Alias('objID', 'ID', 'ObjectId')] [int] $DeviceID, # Base id of the template [ValidateNotNullOrEmpty()] [int] $TemplateBaseID = 1, # Filter text identifier for template tags in a device [ValidateNotNullOrEmpty()] [String] $TemplateTAGNameIdentifier = "Template_", # Compare properties inside a sensor as well as the existence inside the template [switch] $ComparePropertiesInObject, # Output objects that meet the template, as well as diffs to template [switch] $IncludeEqual, # SensorTree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin {} process { Write-Log -LogText "Getting device to validate with object ID $($DeviceID)" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $DevicesToValidate = Get-PRTGDevice -ObjectId $DeviceID -SensorTree $SensorTree Write-Log -LogText "Getting role summary table from templatebase object ID $($TemplateBaseID)" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $TemplateTAGSummary = Show-PRTGTemplateSummaryFromObjectTAG -TemplateBaseID $TemplateBaseID -TemplateTAGNameIdentifier $TemplateTAGNameIdentifier -SensorTree $SensorTree foreach ($Device in $DevicesToValidate) { Write-Log -LogText "Getting roles summary table for object ""$($device.name)"" (objID $($device.ObjID))" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $DeviceTAGSummary = Show-PRTGTemplateSummaryFromObjectTAG -TemplateBaseID $Device.ObjID -TemplateTAGNameIdentifier $TemplateTAGNameIdentifier -SensorTree $SensorTree -IncludeNonMatching $result = @() foreach ($DeviceTAGSummaryItem in $DeviceTAGSummary) { if ($DeviceTAGSummaryItem.rolename) { #if item is a "named" role $Reference = ($DeviceTAGSummaryItem).sensor $Difference = ($TemplateTAGSummary | Where-Object rolename -eq "$($DeviceTAGSummaryItem.RoleName)").sensor if ($Reference -and $Difference) { $ResultItem = Compare-Object -ReferenceObject $Reference -DifferenceObject $Difference -Property Name -PassThru -IncludeEqual if ($ComparePropertiesInObject) { #if comparision on objectdetails/-properties is requested -> compare properties against template foreach ($SensorItem in ($ResultItem | Where-Object SideIndicator -eq "==")) { #get the reference sensor $ReferenceSensor = $Reference | Where-Object name -like $SensorItem.name #compare properties on sensor against template $differentProperty = Compare-ObjectProperty -ReferenceObject $SensorItem -DifferenceObject $ReferenceSensor -PropertyFilter "sensortype", "priority", "sensorkind", "interval", "tags", "Type", "IntervalText", "name" if ($differentProperty) { $SensorItem.SideIndicator += "!" Add-Member -InputObject $SensorItem -MemberType NoteProperty -Force -Name "PropertyDifferenceReport" -Value ( [string]::Join(", ", ($differentProperty | ForEach-Object { "Difference on property $($_.property)=""$($_.Value)"" on $(if($_.SideIndicator -eq '<='){"device"}else{"template"})" })) ) } else { Add-Member -InputObject $SensorItem -MemberType NoteProperty -Force -Name "PropertyDifferenceReport" -Value $null } } } $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name SideIndicatorStatus ` -Value (. { switch ($_.SideIndicator) { '<=' { "WARNING" } '=>' { "WARNING" } '==!' { "WARNING" } '==' { "OK" } } }) } $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicatorDescription" ` -Value (. { switch ($_.SideIndicator) { '<=' { "In device but not in template" } '=>' { "In template but not in device" } '==!' { "Match in device and template, but difference in Properties! Look at PropertyDifferenceReport" } '==' { "Match in device and template" } } }) } } else { #no sensors in device or no sensors in template if (-not $Reference -and $Difference) { #no sensors in device but some sensors in template $ResultItem = $Difference $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicator" -Value "=>" } $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicatorStatus" -Value "WARNING" } $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicatorDescription" -Value "In template but not in device" } } elseif ($Reference -and -not $Difference) { #no sensors in template but some sensors in device $ResultItem = $Reference $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicator" -Value "<=" } $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicatorStatus" -Value "WARNING" } $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicatorDescription" -Value "In device but not in template" } } elseif (-not $Reference -and -not $Difference) { #no sensors in device and no sensors in template $ResultItem = "" $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicator" -Value "!!" } $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicatorStatus" -Value "WARNING" } $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicatorDescription" -Value "No objects found" } } } } else { #if item is a "NonMatching"-object (without a name in RoleName property) $ResultItem = $DeviceTAGSummaryItem.Sensor $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicator" -Value "!!" } $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicatorStatus" -Value "WARNING" } $ResultItem | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Force -Name "SideIndicatorDescription" -Value "Object not matching any template" } } $ResultItem | ForEach-Object { if ($_.pstypenames[0] -ne "PRTG.Object.Compare") { $_.pstypenames.Insert(0, "PRTG.Object.Compare") } } $result += $ResultItem } if (-not $IncludeEqual) { $result = $result | Where-Object SideIndicator -ne '==' } $result } } end {} } function New-PRTGDefaultFolderStructureToProbe { <# .Synopsis New-PRTGDefaultFolderStructureToProbe .DESCRIPTION Copy a new folder/group structure to a destination Primary intension is to copy a tempalte folderstructure to a new probe .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE New-PRTGDefaultFolderStructureToProbe Required values will be queried by gridview-selection .EXAMPLE New-PRTGDefaultFolderStructureToProbe -TemplateFolderStructureID (Get-PRTGObject -Name "Template_group_name") -ProbeID (Get-PRTGProbes | Out-GridView -Title "Please select destination probe" -OutputMode Single) Creates group (folder) structure in a probe from "Template_group_name". All groups beneath the object "Template_group_name" will be copied to the probe selected by the Out-GridView cmdlet .EXAMPLE New-PRTGDefaultFolderStructureToProbe -TemplateFolderStructureID (Get-PRTGGroup -Name "MyTemplateGroup").objId -ProbeID (Get-PRTGProbes "NewProbe").ObjId Copy group structure beneath group "MyTemplateGroup" to the probe "NewProbe" #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'Medium' )] Param( # ID of the group that contains the structure to be copied to the destination probe [ValidateNotNullOrEmpty()] [int] $TemplateFolderStructureID = (Get-PRTGObject -Name "Groups for new customer" -Type group -SensorTree $script:PRTGSensorTree -Verbose:$false | Select-Object -ExpandProperty ObjID), # ID of the destination probe [ValidateNotNullOrEmpty()] [int] $ProbeID = (Get-PRTGProbe -SensorTree $script:PRTGSensorTree -Verbose:$false | Sort-Object fullname | Select-Object Name, objID | Out-GridView -Title "Please select destination probe" -OutputMode Single | Select-Object -ExpandProperty ObjID), # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ( ($_.StartsWith("http")) ) { $true }else { $false } })] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # SensorTree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) $logscope = $MyInvocation.MyCommand.Name #Get tempalte to copy $TemplateFolderStructure = Get-PRTGObject -ID $TemplateFolderStructureID -Type group -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop if (-not $TemplateFolderStructure.group) { Write-Log -LogText "Template folder not found or no groups under structure." -LogType Error -LogScope $logscope -NoFileStatus -Error return } #Get target object $ProbeNewCustomer = Get-PRTGObject -ID $ProbeID -Type probenode -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop if (-not $ProbeNewCustomer) { Write-Log -LogText "No Probe specified." -LogType Error -LogScope $logscope -NoFileStatus -Error return } $count = 0 $TotalCount = $TemplateFolderStructure.group.count $Copied = @() foreach ($item in $TemplateFolderStructure.group) { $count++ Write-Progress -Activity "Copy data structure" -Status "Progress: $count of $($TotalCount)" -PercentComplete ($count / $TotalCount * 100) if ($pscmdlet.ShouldProcess($ProbeNewCustomer.name, "Deploy ""$($item.name)")) { Write-Log -LogText "Deploy objID $($item.ID[0]) ""$($item.name)"" to objID $($ProbeNewCustomer.objID) ""$($ProbeNewCustomer.name)""" -LogType Set -LogScope $logscope -NoFileStatus Remove-Variable ErrorEvent -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false -Confirm:$false try { $CopyObject = Copy-PRTGObject -ObjectId $item.ID[0] -TargetID $ProbeNewCustomer.ObjID -Name $item.name -Server $Server -User $User -Pass $Pass -SensorTree $SensorTree -Verbose:$false -ErrorVariable ErrorEvent -ErrorAction Stop Enable-PRTGObject -ObjectId $CopyObject.objid -Force -NoWaitOnStatus -Server $Server -User $User -Pass $Pass -SensorTree $SensorTree -Verbose:$false -ErrorVariable ErrorEvent -ErrorAction Stop $Copied += $CopyObject Remove-Variable CopyObject -Scope script -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false -Confirm:$false } catch { Write-Log -LogText "Error occured while deploying new folder structure! $($_.exception.message)" -LogType Error -LogScope $logscope -Error -NoFileStatus return } } Remove-Variable item -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false -Confirm:$false } Write-Log -LogText "$($Copied.count) objects copied" -LogType Info -LogScope $logscope -NoFileStatus Write-Log -LogText "Refresh PRTG SensorTree" -LogType Query -LogScope $logscope -NoFileStatus $SensorTree = Invoke-PRTGSensorTreeRefresh -Server $Server -User $User -Pass $Pass -PassThru -Verbose:$false } function New-PRTGDeviceFromTemplate { <# .Synopsis New-PRTGDeviceFromTemplate .DESCRIPTION Creates a new device out of a template structure, where operatingsystems and operatingsystem roles are separates in different templates. .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE New-PRTGDeviceFromTemplate -DeviceName "NewDevice" Will create new device "NewDevice". Template information will be queried by Out-GridView. .EXAMPLE New-PRTGDeviceFromTemplate -DeviceName "NewDevice" -HostName "NewDevice.ad.corp.com" -TemplateSystem (Get-PRTGDevice -Name "Template_MyServerOS").ObjId -TemplateRole (Get-PRTGDevice -Name "Template_FileServer").ObjId -Destination (Get-PRTGProbe "NewProbe").ObjId Create a new device "NewDevice" from specified Systems. #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'Medium' )] Param( # The DisplayName of new system [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String] $DeviceName, # The actual hostname for new system. If not specified, the DeviceName will be used [ValidateNotNullOrEmpty()] [String] $Hostname, # The ID for the system that acts as a template [int] $TemplateSystem = (Get-PRTGObject -Name "Basic operatingsystem" -Recursive -Type device -SensorTree $script:PRTGSensorTree | Sort-Object Fullname | Select-Object fullname, objID | Out-GridView -Title "Please specify operatingsystem for new system" -OutputMode Single | Select-Object -ExpandProperty ObjID), # The ID(s) of the template roles to apply to new device [int[]] $TemplateRole = (Get-PRTGObject -Name "Specific roles" -Recursive -Type device -SensorTree $script:PRTGSensorTree | Sort-Object Fullname | Select-Object FullName, objID | Out-GridView -Title "Please select roles for new system" -OutputMode Multiple | Select-Object -ExpandProperty ObjID), # Filter for sensor names to be excluded from template [string[]] $TemplateSensorFilter = "", # The ID of the destination group [ValidateNotNullOrEmpty()] [int] $Destination = (Get-PRTGObject -Type group -SensorTree $script:PRTGSensorTree | Sort-Object Fullname | Select-Object FullName, objID | Out-GridView -Title "Please select destination for new system" -OutputMode Single | Select-Object -ExpandProperty ObjID), # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ( ($_.StartsWith("http")) ) { $true } else { $false } })] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) [array]$CopyObjectCollection = @() if (-not $Hostname) { $Hostname = $DeviceName } [String]$TemplateTAGName = "Template_*" #check if device currently existis in the destination Write-Log -LogText "Check if device already existis in the destination" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus $DestinationContent = Get-PRTGObject -ID $Destination -Recursive -SensorTree $SensorTree -Verbose:$false -ErrorAction SilentlyContinue | Where-Object Type -like "device" $Device = Get-PRTGObject -Name $DeviceName -Type device -SensorTree $SensorTree -Verbose:$false -ErrorAction SilentlyContinue if ($Device -and ($Device.name -in $DestinationContent.name)) { Write-Log -LogText "$DeviceName ist unter ""$((Get-PRTGObject -ID $Destination -SensorTree $SensorTree -Verbose:$false).fullname)"" bereits vorhanden!" -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Warning $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "" $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "" $choices = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) $caption = "Warning!" $message = "$DeviceName`nist unter `n$((Get-PRTGObject -ID $Destination -SensorTree $SensorTree -Verbose:$false).fullname)`nbereits vorhanden!`n`nSoll das Device wirklich doppelt angelegt werden?" $result = $Host.UI.PromptForChoice($caption, $message, $choices, 1) if ($result -eq 1) { Write-Log -LogText "Abbruch..." -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Warning return } } Remove-Variable result, message, caption, choices, no, yes, device, DestinationContent -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false #Start cloning # Get "OS"-Device Write-Log -LogText "Start cloning devicetemplate to destination ID $Destination" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus $TemplateSystemDevice = Get-PRTGObject -ID $TemplateSystem -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop if (-not $TemplateSystemDevice) { Write-Log -LogText "Template not found!" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error; return } #clone to destination group and set hostname if ($pscmdlet.ShouldProcess("Object with ID $($Destination)", "Deploy new device ""$($DeviceName)"" from template ""$($TemplateSystemDevice.name)""")) { $NewCustomerServer = Copy-PRTGObject -ObjectId $TemplateSystemDevice.ObjID -TargetID $Destination -Name $DeviceName -Server $Server -User $User -Pass $Pass -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop if ($NewCustomerServer) { Set-PRTGObjectProperty -ObjectId $NewCustomerServer.ObjID -PropertyName host -PropertyValue $Hostname -Server $Server -User $User -Pass $Pass -Verbose:$false -ErrorAction Stop } else { Write-Log -LogText "Error after copy " } $CopyObjectCollection += $NewCustomerServer } #if there are roles specified, query sensors from role-templates and clone them to the new system if ($TemplateRole) { #Query roles and select the sensors Write-Log -LogText "Query role specific sensor(s) from $($TemplateRole.count) role template(s)" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus [array]$TemplateSensorsToCopy = Get-PRTGObject -ID $TemplateRole -Recursive -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop | Where-Object Type -like "sensor" Write-Log -LogText "Found $($TemplateSensorsToCopy.count) role specific sensor(s)" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus #Filtering out sensors excluded from deployment process if ($TemplateSensorFilter) { Write-Log -LogText "Filtering out role specific sensor(s) from (Filter: $([string]::Join(", ",$TemplateSensorFilter)))" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus foreach ($filter in $TemplateSensorFilter) { $TemplateSensorsToCopy = $TemplateSensorsToCopy | Where-Object name -NotLike $filter } Write-Log -LogText "$($TemplateSensorsToCopy.count) role specific sensor(s) left to clone after filtering" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus } #Start deployment of role sensors if ($TemplateSensorsToCopy) { Write-Log -LogText "Start deployment of $($TemplateSensorsToCopy.count) role specific sensor(s)" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus $script:count = 0 $script:TotalCount = $TemplateSensorsToCopy.count $ProgressID = 16364 #random choosen number to produce a new progress bar foreach ($item in $TemplateSensorsToCopy) { $script:count++ Write-Progress -Activity "Copy role sensors" -Status "Progress: $script:count of $($script:TotalCount)" -PercentComplete ($script:count / $script:TotalCount * 100) -id $ProgressID if ($pscmdlet.ShouldProcess($NewCustomerServer.name, "Deploy ""$($item.name)")) { Write-Log -LogText "Deploy ""$($item.name)"" to ""$($NewCustomerServer.name)""" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus Remove-Variable ErrorEvent -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false try { #copy object $SensorCopy = Copy-PRTGObject -ObjectId $item.ObjID -TargetID $NewCustomerServer.ObjID -Name $item.name -Server $Server -User $User -Pass $Pass -SensorTree $SensorTree -Verbose:$false -ErrorVariable ErrorEvent -ErrorAction Stop Write-Log -LogText "New sensor copied (objID:$($SensorCopy.objid) name:""$($SensorCopy.name))""" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput #enable object Write-Log -LogText "Activate / unpause new sensor" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput Enable-PRTGObject -ObjectId $SensorCopy.objid -Server $Server -User $User -Pass $Pass -SensorTree $SensorTree -Force -Verbose:$false -ErrorVariable ErrorEvent -ErrorAction Stop #Add tags from template to new device Write-Log -LogText "Setting tags from role template to ""$($NewCustomerServer.name)""" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput [Array]$DeviceTAG = Get-PRTGObjectTAG -ObjectID $item.ParentNode.id[0] -SensorTree $SensorTree -Verbose:$false -ErrorVariable ErrorEvent -ErrorAction Stop | Where-Object { $_ -like $TemplateTAGName } [Array]$DeviceTAG += Get-PRTGObjectTAG -ObjectID $item.ObjID -SensorTree $SensorTree -Verbose:$false -ErrorVariable ErrorEvent -ErrorAction Stop | Where-Object { $_ -like $TemplateTAGName } if ($DeviceTAG) { #$SensorTree = Get-PRTGSensorTree -Server $Server -User $User -Pass $Pass #Write TAG to Device Add-PRTGObjectTAG -ObjectId $NewCustomerServer.ObjID -TAGName $DeviceTAG -Force -Server $Server -User $User -Pass $Pass -SensorTree $SensorTree -Verbose:$false -ErrorVariable ErrorEvent -ErrorAction Stop #Write TAG to Sensor Add-PRTGObjectTAG -ObjectId $SensorCopy.ObjID -TAGName $DeviceTAG -Force -Server $Server -User $User -Pass $Pass -SensorTree $SensorTree -Verbose:$false -ErrorVariable ErrorEvent -ErrorAction Stop } #status output [array]$CopyObjectCollection += $SensorCopy Write-Log -LogText "$($CopyObjectCollection.Count) sensors created until now." -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus Remove-Variable x -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false } catch { #Write-Log -LogText $ErrorEvent.Message -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error Write-Log -LogText $_.exception.message -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error } } Write-Progress -Activity "Copy role sensors" -id $ProgressID -Completed } } else { Write-Log -LogText "No role specific sensors to deploy" -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus } } else { Write-Log -LogText "No role template selected" -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus } if ($pscmdlet.ShouldProcess($NewCustomerServer.name, "Resume from pause status")) { Write-Log -LogText "Resume ""$($NewCustomerServer.name)"" from pause status" -LogType set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus Enable-PRTGObject -ObjectId $NewCustomerServer.ObjID -Server $Server -User $User -Pass $Pass -Force -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop Invoke-PRTGObjectRefresh -ObjectId $NewCustomerServer.ObjID -Server $Server -User $User -Pass $Pass -Verbose:$false -ErrorAction Stop } if ($SensorTree) { Write-Log -LogText "Refresh SensorTree" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus Invoke-PRTGSensorTreeRefresh -Server $Server -User $User -Pass $Pass -Verbose:$false } return $CopyObjectCollection } function Show-PRTGTemplateSummaryFromObjectTAG { <# .Synopsis Show-PRTGTemplateRoles .DESCRIPTION Display a list of template roles found under a groups and devices under a prtg structure .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Show-PRTGTemplateSummaryFromObjectTAG Display list of tags witch began with "Template_" and can be found under PRTG Core Server object. This is the default set of parameters. .EXAMPLE Show-PRTGTemplateSummaryFromObjectTAG -TemplateBaseID 100 Display a list of tags witch began with "Template_" and are based under the group or device with the object ID 100. .EXAMPLE Show-PRTGTemplateSummaryFromObjectTAG -TemplateBaseID 100 -TemplateTAGNameIdentifier "MyPersonalTemplate-" Display a list of tags witch began with "MyPersonalTemplate-" and are based under the group or device with the object ID 100. #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( # ID of the object to copy [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( {$_ -gt 0})] [Alias('objID', 'ID', 'ObjectId')] [int] $TemplateBaseID = 1, # Filter value to identify template tags [ValidateNotNullOrEmpty()] [ValidateScript( {$_ -notcontains ("*", "?")})] [string] $TemplateTAGNameIdentifier = "Template_", # Include matching as non matching objects [switch] $IncludeNonMatching, # SensorTree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin {} process { #Build Template Role object for comparing against devices $TemplateRoleDevices = Get-PRTGObject -ObjectID $TemplateBaseID -Recursive -Type group, device -SensorTree $SensorTree | Where-Object tags -Match ([regex]::Escape($TemplateTAGNameIdentifier)) $TemplateRoleDevicesTypeGroup = $TemplateRoleDevices | Group-Object type -NoElement | Select-Object Count, Name, @{N = "Text"; E = { "$($_.count) $($_.Name.tolower())$(if($_.count -ne 1){"s"})"}} #Start to create new object if ($TemplateRoleDevices.tags) { [array]$TemplateRoles = $TemplateRoleDevices.tags.split(' ') | Where-Object { $_ -Match ([regex]::Escape($TemplateTAGNameIdentifier)) } | Sort-Object -Unique | ForEach-Object { New-Object -TypeName psobject -Property @{"RoleName" = $_ } } Write-Log -LogText "Found $($TemplateRoles.count) role$(if($TemplateRole.count -ne 1){"s"}) from $([string]::Join("and ",$TemplateRoleDevicesTypeGroup.Text)) in templatebase object ID $TemplateBaseID" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput } else { Write-Log -LogText "No template roles found in object ID $TemplateBaseID" -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput return } foreach ($TemplateRole in $TemplateRoles) { Write-Log -LogText "Building object for ""$($TemplateRole.RoleName)"" from $([string]::Join("and ",$TemplateRoleDevicesTypeGroup.Text)) under templatebase object ID $TemplateBaseID" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput [array]$device = $TemplateRoleDevices | Where-Object {$_.tags.split(' ') -eq $TemplateRole.RoleName} Add-Member -InputObject $TemplateRole -MemberType NoteProperty -Force -Name DeviceCount -Value ([array]($device | Where-Object objId -ne $TemplateBaseID)).count Add-Member -InputObject $TemplateRole -MemberType NoteProperty -Force -Name Device -Value ([array]($device | Where-Object objId -ne $TemplateBaseID)) if ($device.sensor) { [array]$sensor = $device.sensor | Where-Object {$_.tags.split(' ') -eq $TemplateRole.RoleName} Add-Member -InputObject $TemplateRole -MemberType NoteProperty -Force -Name SensorCount -Value $sensor.count Add-Member -InputObject $TemplateRole -MemberType NoteProperty -Force -Name Sensor -Value ([array](Set-TypesNamesToPRTGObject -PRTGObject $sensor)) } else { Add-Member -InputObject $TemplateRole -MemberType NoteProperty -Force -Name SensorCount -Value 0 Add-Member -InputObject $TemplateRole -MemberType NoteProperty -Force -Name Sensor -Value $null } Remove-Variable device, sensor -Force -ErrorAction Ignore -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false } if ($IncludeNonMatching) { Write-Log -LogText "Searching for objects not matching TAG-identifier ""$($TemplateTAGNameIdentifier)"" in $([string]::Join("and ",$TemplateRoleDevicesTypeGroup.Text)) under templatebase object ID $TemplateBaseID" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput [array]$device = $TemplateRoleDevices | Where-Object {$_.tags -notmatch ([regex]::Escape($TemplateTAGNameIdentifier))} [array]$sensor = $TemplateRoleDevices.sensor | Where-Object {$_.tags -notmatch ([regex]::Escape($TemplateTAGNameIdentifier))} if ( ($device | Where-Object objId -ne $TemplateBaseID) -or ($sensor) ) { Write-Log -LogText "found non matching objects. Inserting an empty RoleName object." -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $TemplateRoles += New-Object -TypeName psobject -Property @{ "RoleName" = "" "DeviceCount" = if ($device | Where-Object objId -ne $TemplateBaseID) { ([array]($device | Where-Object objId -ne $TemplateBaseID)).count } else { 0 } "Device" = if ($device | Where-Object objId -ne $TemplateBaseID) { ([array]($device | Where-Object objId -ne $TemplateBaseID)) } else { $null } "SensorCount" = if ($sensor) { $sensor.Count } else { 0 } "Sensor" = if ($sensor) { [array]([array](Set-TypesNamesToPRTGObject -PRTGObject $sensor)) } else { $null } } } Remove-Variable device, sensor -Force -ErrorAction Ignore -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false } $TemplateRoles } end {} } function Get-PRTGDevice { <# .Synopsis Get-PRTGDevice .DESCRIPTION Returns one or more devices from sensortree .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Get-PRTGDevice Query all devices from the default sensortree (global variable after connect to PRTG server) .EXAMPLE Get-PRTGDevice -SensorTree $SensorTree Query devices by name from a non default sensortree .EXAMPLE Get-PRTGDevice -Name "Device01" Query devices by name .EXAMPLE Get-PRTGDevice -Name "Device01", "Device*" Multiple names are possible .EXAMPLE "Device01" | Get-PRTGDevice Piping is also possible .EXAMPLE Get-PRTGDevice -ObjectId 1 Query devices by object ID .EXAMPLE 1 | Get-PRTGDevice Piping is also possible #> [CmdletBinding( DefaultParameterSetName = 'ReturnAll', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( # ID of the PRTG object [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'ID', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 })] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # Name of the device [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'Name', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [String[]] $Name, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin { $queryParam = @{ "Type" = "device" "SensorTree" = $SensorTree "Verbose" = $false } } process { $result = @() switch ($PsCmdlet.ParameterSetName) { 'ID' { New-Variable -Name result -Force foreach ($item in $ObjectId) { $result += Get-PRTGObject -ObjectID $item @queryParam } } 'Name' { foreach ($item in $Name) { $result += Get-PRTGObject -Name $item @queryParam } } Default { $result = Get-PRTGObject @queryParam } } $result } end {} } function Get-PRTGGroup { <# .Synopsis Get-PRTGGroup .DESCRIPTION Returns one or more groups from sensortree .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Get-PRTGGroup Query all groups from the default sensortree (global variable after connect to PRTG server) .EXAMPLE Get-PRTGGroup -SensorTree $SensorTree Query groups by name from a non default sensortree .EXAMPLE Get-PRTGGroup -Name "Group01" Query groups by name .EXAMPLE Get-PRTGGroup -Name "Group01", "Group*" Multiple names are possible .EXAMPLE "Group01" | Get-PRTGGroup Piping is also possible .EXAMPLE Get-PRTGGroup -ObjectId 1 Query groups by object ID .EXAMPLE 1 | Get-PRTGGroup Piping is also possible #> [CmdletBinding( DefaultParameterSetName = 'ReturnAll', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( # ID of the PRTG object [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'ID', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 })] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # Name of the group [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'Name', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [String[]] $Name, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin { $queryParam = @{ "Type" = "group" "SensorTree" = $SensorTree "Verbose" = $false } } process { $result = @() switch ($PsCmdlet.ParameterSetName) { 'ID' { foreach ($item in $ObjectId) { $result += Get-PRTGObject -ObjectID $item @queryParam } } 'Name' { foreach ($item in $Name) { $result += Get-PRTGObject -Name $item @queryParam } } Default { $result = Get-PRTGObject @queryParam } } $result } end {} } function Add-PRTGObjectTAG { <# .Synopsis Add-PRTGObjectTAG .DESCRIPTION Add a text to the tags property of an PRTG object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Add-PRTGObjectTAG -ObjectId 1 -TAGName "NewName" Add TAG "NewName" to object 1 #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] Param( # ID of the object to pause/resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 })] [Alias('ObjID', 'ID')] [int] $ObjectId, # Name of the object's property to set [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $false)] [ValidateNotNullOrEmpty()] [string[]] $TAGName, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ( ($_.StartsWith("http")) ) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree, # skip errors if an tag is not present [Switch] $Force, # returns the changed object [Switch] $PassThru ) Begin {} Process { foreach ($ID in $ObjectId) { $break = $false #Get the object Write-Log -LogText "Gather object tags from object ID $ID." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput try { $Object = Get-PRTGObject -ID $ID -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop } catch { Write-Log -LogText $_.exception.message -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error break } #Build and check TAG lists if ($Object.tags) { [array]$TAGListExisting = $Object.tags.Split(' ') } $TAGListToAdd = @() foreach ($TAG in $TAGName) { if ($TAG.Contains(' ')) { Write-Log -LogText "The tag ""$($TAG)"" contains invalid space characters! Space characters will be removed." -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Warning $TAG = $TAG.Replace(' ', '') } if ($TAG -in $TAGListExisting) { if ($Force) { Write-Log -LogText "Skipping tag ""$($TAG)"", because it is already set on object id $ID" -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Warning } else { Write-Log -LogText "Tag ""$($TAG)"" is already set on object id $ID" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error $break = $true break } } else { $TAGListToAdd += $TAG } } if ($break) { break } if ($TAGListExisting) { $TAGListToSet = "$($TAGListExisting) $([string]::Join(' ',$TAGListToAdd))" } else { $TAGListToSet = [string]::Join(' ', $TAGListToAdd) } $TAGListToSet = $TAGListToSet.Trim() #set TAG list to PRTG object if ($TAGListToAdd) { $MessageText = "Add $($TAGListToAdd.count) $(if($TAGListToAdd.count -eq 1) {"tag"} else {"tags"}) ($([string]::Join(' ',$TAGListToAdd)))" if ($pscmdlet.ShouldProcess("objID $ID", $MessageText)) { Write-Log -LogText $MessageText -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput try { #Set in PRTG Set-PRTGObjectProperty -ObjectId $ID -PropertyName tags -PropertyValue $TAGListToSet -Server $Server -User $User -Pass $Pass -ErrorAction Stop -Verbose:$false #Set on object to return $Object.tags = $TAGListToSet #Set in SensorTree variable $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($ID)]/tags").InnerText = $TAGListToSet } catch { Write-Log -LogText $_.exception.message -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error if (-not $Force) { break } } } } else { Write-Log -LogText "No tags to set. Skipping object ID $($Object.objId)" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput } #output the object if ($PassThru) { $Object } #clear up the variable mess Remove-Variable TAG, TAGListExisting, TAGListToAdd, TAGListToSet, Object, MessageText -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false } } End {} } function Copy-PRTGObject { <# .Synopsis Copy-PRTGObject .DESCRIPTION Copy a PRTG Object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt adopted from PSGallery Module "PSPRTG" Author: Sam-Martin Github: https://github.com/Sam-Martin/prtg-powershell .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Copy-PRTGObject -ObjectId 1 -TargetID 2 -Name "NewName" Duplicates object 1 to group with ID 2 with name "NewName". #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'Medium' )] Param( # ID of the object to copy [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('SourceID', 'objID')] [int] $ObjectID, # ID of the target parent object [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [int] $TargetID, # Name of the newly cloned object [string] $Name, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if (($_.StartsWith("http"))) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # Sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin {} process { $body = @{ id = $ObjectId name = $Name targetid = $TargetID username = $User passhash = $Pass } # get source object from sensor tree try { $SourceObject = Get-PRTGObject -ObjectID $ObjectID -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop if (-not $Name) { $body.name = $SourceObject.name } } catch { Write-Log -LogText "Cannot find object to clone. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -Error -NoFileStatus return } # get target object from sensor tree try { $TargetObject = Get-PRTGObject -ObjectID $TargetID -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop } catch { Write-Log -LogText "Cannot find target object. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -Error -NoFileStatus return } if ($pscmdlet.ShouldProcess("objID $TargetID '$($TargetObject.Name)'", "Clone object id $($SourceObject.ObjID) as '$Name'")) { #Try to clone the object try { Write-Log -LogText "Try to clone $($SourceObject.Type) with objID $($SourceObject.ObjID) to target with objID $TargetID. New name of the $($SourceObject.Type) in the target: ""$Name"" ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $Result = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/duplicateobject.htm" -Method Get -Body $body -Verbose:$false -Debug:$false } catch { Write-Log -LogText "Failed to clone object $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -Error -NoFileStatus return } Write-Log -LogText "$($SourceObject.Type) cloned to targetID $TargetID. Try to recieve new object from prtg ($Server)" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput # Pluralise the type. Needed for receiving the copied object by "type" $TypePlural = $SourceObject.Type + 's' # Fetch the ID of the object we just added [array]$result = (Receive-PRTGObject -numResults 100 -columns "objid,name,type,tags,active,status" -SortBy "objid" -content $TypePlural -Filters @{"filter_name" = $Name } -Server $Server -User $User -Pass $Pass -Verbose:$false).$TypePlural.item | Where-Object objid -ne $ObjectId #output the object if result contains an objectID if ($result.ObjID) { #check for duplicated results if ($Result.Count -gt 1) { Write-Log -LogText "Recieve $($Result.Count) $TypePlural from prtg ($Server). Assume highest ID as the new $($SourceObject.Type)." -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $result = $result | Sort-Object -Property objid -Descending | Select-Object -First 1 } else { Write-Log -LogText "Recieve $($Result.Count) $($SourceObject.Type) ($($Result.objid)) from prtg ($Server)." -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput } $newChild = $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($ObjectID)]").CloneNode($true) $newObjectInSensorTree = $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($TargetID)]").AppendChild( $newChild ) $newObjectInSensorTree.SetAttribute("id", $Result.objID) $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($TargetID)]//*[id=$($ObjectID)]/name").InnerText = $Result.name $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($TargetID)]//*[id=$($ObjectID)]/url").InnerText = $newObjectInSensorTree.url.Split('=')[0] + '=' + $Result.objID $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($TargetID)]//*[id=$($ObjectID)]/id").InnerText = $Result.objID # Ouput result $Result = Get-PRTGObject -ObjectID $Result.objID -SensorTree $SensorTree -Verbose:$false $Result } else { #if result contains an empty item Write-Log -LogText "No items recieved after cloning! Unkown issue ($Server)." -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error Remove-Variable result -Force -ErrorAction SilentlyContinue -Verbose:$false -Debug:$false -WhatIf:$false return } } } end {} } function Disable-PRTGObject { <# .Synopsis Disable-PRTGObject .DESCRIPTION Pause an PRTG object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt adopted from PSGallery Module "PSPRTG" Author: Sam-Martin Github: https://github.com/Sam-Martin/prtg-powershell .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Disable-PRTGObject -ObjectId 1 Disable object with ID 1 for unlimited time No message is used. .EXAMPLE Disable-PRTGObject -ObjectId 1 -Message "Done by User01" Disable object with ID 1 for unlimited time with specified message. .EXAMPLE Disable-PRTGObject -ObjectId 1 -Message "Done by User01" -Minutes 1 Disable object with ID 1 for one minute with specified message. #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] Param( # ID of the object to pause [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('ObjID')] [int[]] $ObjectId, # Message to associate with the pause event [string] $Message, # Length of time in minutes to pause the object, $null for indefinite [int] $Minutes = $null, # do action regardless of current status of sensor [Switch] $Force, # Not waiting for sensor status update in PRTG server (faster reply on large batch jobs) [Switch] $NoWaitOnStatus, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # Sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin {} process { foreach ($id in $ObjectId) { $body = @{ id = $id action = 0 username = $User passhash = $Pass } if ($Minutes) { $body.Add("duration", $Minutes) } if ($Message) { $body.Add("pausemsg", $Message) } if ($pscmdlet.ShouldProcess("objID $Id", "Disable PRTG object")) { try { if ($Minutes) { Write-Log -LogText "Disable object ID $id for $Minutes minutes. $(if($Message){"Message:$Message "})($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput } else { Write-Log -LogText "Permanent disable object ID $id. $(if($Message){"Message:$Message "})($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput } $StatusBefore = Receive-PRTGObjectStatus -ObjectID $id -Server $Server -User $User -Pass $Pass -Verbose:$false if ( ($StatusBefore.status_raw -notin (7, 8, 9, 12)) -or $Force ) { $null = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/pause$(if($Minutes){"objectfor"}).htm" -Method Get -Body $body -Verbose:$false -Debug:$false -ErrorAction Stop } else { Write-Log -LogText "Object ID $id is already disabled" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error break } if ($NoWaitOnStatus) { if ($Minutes) { $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($ID)]/status_raw").InnerText = 12 } else { $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($ID)]/status_raw").InnerText = 7 } } else { $break = $false do { $StatusAfter = Receive-PRTGObjectStatus -ObjectID $id -Server $Server -User $User -Pass $Pass -Verbose:$false if ($StatusBefore.status_raw -ne $StatusAfter.status_raw) { $break = $true } Start-Sleep -Seconds 1 } until ($break) $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($ID)]/status_raw").InnerText = $StatusAfter.status_raw } } catch { Write-Log -LogText "Failed to disable object ID $id. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error break } } } } end {} } function Enable-PRTGObject { <# .Synopsis Enable-PRTGObject .DESCRIPTION Enables an (paused) PRTG object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt adopted from PSGallery Module "PSPRTG" Author: Sam-Martin Github: https://github.com/Sam-Martin/prtg-powershell .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Enable-PRTGObject -ObjectId 1 Enables object with ID 1 #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] Param( # ID of the object to resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # do action regardless of current status of sensor [Switch] $Force, # Not waiting for sensor status update in PRTG server (faster reply on large batch jobs) [Switch] $NoWaitOnStatus, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # Sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin {} process { foreach ($id in $ObjectId) { $body = @{ id = $id action = 1 username = $User passhash = $Pass } $StatusBefore = Receive-PRTGObjectStatus -ObjectID $id -Server $Server -User $User -Pass $Pass -Verbose:$false if (-not $StatusBefore) { Write-Log "Failed to current status for object ID $id. Skipping object" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error break } if ($pscmdlet.ShouldProcess("objID $Id", "Enable PRTG object")) { try { #Enable in PRTG Write-Log -LogText "Enable object ID $id ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput if ( ($StatusBefore.status_raw -in (7, 8, 9, 12)) -or $Force ) { $null = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/pause.htm" -Method Get -Body $Body -Verbose:$false -Debug:$false -ErrorAction Stop } else { Write-Log -LogText "Object ID $id is already enabled" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error break } } catch { Write-Log -LogText "Failed to enable object ID $id. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error break } #Receive new status $SafeguardBreakCount = 15 $count = 0 if ($NoWaitOnStatus) { $break = $true } else { $break = $false } do { $StatusAfter = Receive-PRTGObjectStatus -ObjectID $id -Server $Server -User $User -Pass $Pass -Verbose:$false if ($StatusBefore.status_raw -ne $StatusAfter.status_raw) { $break = $true } if ($count -ge $SafeguardBreakCount) { Write-Log -LogText "Error receiving enable-status from object $id! break status query." -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error $break = $true } Start-Sleep -Seconds 1 $count ++ } until($break) #Set in SensorTree variable $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($ID)]/status_raw").InnerText = $StatusAfter.status_raw } } } end {} } function Find-PRTGObject { <# .Synopsis Find-PRTGObject .DESCRIPTION Find objects from sensortree by various criteria .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Find-PRTGObject -ByTAGName "Server" Find-PRTGObject -ByTAGName "Template_*" -IncludeInherited Find-PRTGObject -ByTAGName "Template_*", "Server" .EXAMPLE Find-PRTGObject -ByStatus "Warning" Find-PRTGObject -ByStatus 'Paused by User', "Down" .EXAMPLE Find-PRTGObject -BySensorType POP3 Find-PRTGObject -BySensorType POP3, DNS #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( # Name of TAG to query objects [Parameter(Mandatory = $true, ParameterSetName = 'ByTAGName')] [string[]] $ByTAGName, # Indicates the search is case sensitive [Parameter(ParameterSetName = 'ByTAGName')] [switch] $CaseSensitive, # Include inherited [Parameter(ParameterSetName = 'ByTAGName')] [switch] $IncludeInherited, # The Status to query on objects [Parameter(Mandatory = $true, ParameterSetName = 'ByStatus')] [ValidateSet("Unknown", "Scanning", "Up", "Warning", "Down", "No Probe", "Paused by User", "Paused by Dependency", "Paused by Schedule", "Unusual", "Not Licensed", "Paused Until")] [string[]] $ByStatus, # The type of sensor to query [Parameter(Mandatory = $true, ParameterSetName = 'BySensorType')] [ValidateSet('Cloud HTTP', 'Cloud Ping', 'Serverzustand', 'DNS', 'VMWare Hostserver Hardware-Zustand (SOAP)', 'VMware Hostserver Leistung (SOAP)', 'Exchange Sicherung (Powershell)', 'Exchange Datenbank (Powershell)', 'Exchange Datenbank DAG (Powershell)', 'Exchange Postfach (Powershell)', 'Exchange Nachrichtenwarteschlange (Powershell)', 'Programm/Skript', 'Programm/Skript (Erweitert)', 'Datei-Inhalt', 'Ordner', 'FTP', 'Green IT', 'HTTP', 'HTTP (Erweitert)', 'Hyper-V Freigegebenes Clustervolume', 'IMAP', 'Windows Updates Status (Powershell)', 'Leistungsindikator IIS Anwendungspool', 'Ping', 'POP3', 'Port', 'Zustand der Probe', 'Active Directory Replikationsfehler', 'Windows Druckwarteschlange', 'WSUS-Statistiken', 'RDP (Remote Desktop)', 'Freigaben-Speicherplatz', 'SMTP', 'SNMP Prozessorlast', 'SNMP (Benutzerdef.)', 'SNMP-Zeichenfolge', 'SNMP Dell EqualLogic Physikalischer Datenträger', 'SNMP Dell PowerEdge Physikalischer Datenträger', 'SNMP SonicWALL Systemzustand', 'SNMP Dell PowerEdge Systemzustand', 'SNMP Plattenplatz', 'SNMP-Bibliothek', 'SNMP Linux Durchschnittl. Last', 'SNMP Linux Speicherinfo', 'SNMP Linux Physikalischer Datenträger', 'SNMP Speicher', 'SNMP QNAP Logischer Datenträger', 'SNMP QNAP Physikalischer Datenträger', 'SNMP QNAP Systemzustand', 'SNMP RMON', 'SNMP-Datenverkehr', 'SNMP-Laufzeit', 'SNTP', 'SSL-Sicherheitsüberprüfung', 'SSL-Zertifikatssensor', 'Systemzustand', 'SNMP-Trap-Empfänger', 'VMware Virtual Machine (SOAP)', 'VMware Datastore (SOAP)', 'Ereignisprotokoll (Windows API)', 'WMI Sicherheits-Center', 'WMI Laufwerkskapazität (mehrf.)', 'WMI Ereignisprotokoll', 'WMI Exchange Transportwarteschlange', 'Hyper-V Virtuelle Maschine', 'Hyper-V Host Server', 'Hyper-V Virtuelles Speichergerät', 'Windows IIS-Anwendung', 'WMI Logischer Datenträger E/A BETA', 'WMI Arbeitsspeicher', 'WMI Netzwerkadapter', 'WMI Auslagerungsdatei', 'Windows Physikalischer Datenträger E/A BETA', 'Windows Prozess', 'Windows Prozessorlast', 'WMI Dienst', 'WMI Freigabe', 'WMI Microsoft SQL Server 2012', 'WMI Terminaldienste (Windows 2008+)', 'Windows Systemlaufzeit', 'WMI UTC-Zeit', 'WMI Wichtige Systemdaten (v2)', 'WMI Datenträger')] [String[]] $BySensorType, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin { $StatusMapping = @{ "Unknown" = 1 "Scanning" = 2 "Up" = 3 "Warning" = 4 "Down" = 5 "No Probe" = 6 "Paused by User" = 7 "Paused by Dependency" = 8 "Paused by Schedule" = 9 "Unusual" = 10 "Not Licensed" = 11 "Paused Until" = 12 } <# $SensorTypeMapping = @{ 'Cloud HTTP' = 'cloudhttp' 'Cloud Ping' = 'cloudping' 'Serverzustand' = 'corestate' 'DNS' = 'dns' 'VMWare Hostserver Hardware-Zustand (SOAP)' = 'esxserverhealthsensorextern' 'VMware Hostserver Leistung (SOAP)' = 'esxserversensorextern' 'Exchange Sicherung (Powershell)' = 'exchangepsbackup' 'Exchange Datenbank (Powershell)' = 'exchangepsdatabase' 'Exchange Datenbank DAG (Powershell)' = 'exchangepsdatabasedag' 'Exchange Postfach (Powershell)' = 'exchangepsmailbox' 'Exchange Nachrichtenwarteschlange (Powershell)' = 'exchangepsmailqueue' 'Programm/Skript' = 'exe' 'Programm/Skript (Erweitert)' = 'exexml' 'Datei-Inhalt' = 'filecontent' 'Ordner' = 'folder' 'FTP' = 'ftp' 'Green IT' = 'green' 'HTTP' = 'http' 'HTTP (Erweitert)' = 'httpadvanced' 'Hyper-V Freigegebenes Clustervolume' = 'hypervcsvdiskfree' 'IMAP' = 'imap' 'Windows Updates Status (Powershell)' = 'lastwindowsupdate' 'Leistungsindikator IIS Anwendungspool' = 'pciisapppool' 'Ping' = 'ping' 'POP3' = 'pop3' 'Port' = 'port' 'Zustand der Probe' = 'probestate' 'Active Directory Replikationsfehler' = 'ptfadsreplfailurexml' 'Windows Druckwarteschlange' = 'ptfprintqueue' 'WSUS-Statistiken' = 'ptfwsusstatistics' 'RDP (Remote Desktop)' = 'remotedesktop' 'Freigaben-Speicherplatz' = 'smbdiskspace' 'SMTP' = 'smtp' 'SNMP Prozessorlast' = 'snmpcpu' 'SNMP (Benutzerdef.)' = 'snmpcustom' 'SNMP-Zeichenfolge' = 'snmpcustomstring' 'SNMP Dell EqualLogic Physikalischer Datenträger' = 'snmpdellequallogicphysicaldisk' 'SNMP Dell PowerEdge Physikalischer Datenträger' = 'snmpdellphysicaldisk' 'SNMP SonicWALL Systemzustand' = 'snmpdellsonicwallsystemhealth' 'SNMP Dell PowerEdge Systemzustand' = 'snmpdellsystemhealth' 'SNMP Plattenplatz' = 'snmpdiskfree' 'SNMP-Bibliothek' = 'snmplibrary' 'SNMP Linux Durchschnittl. Last' = 'snmplinuxloadavg' 'SNMP Linux Speicherinfo' = 'snmplinuxmeminfo' 'SNMP Linux Physikalischer Datenträger' = 'snmplinuxphysicaldisk' 'SNMP Speicher' = 'snmpmemory' 'SNMP QNAP Logischer Datenträger' = 'snmpqnaplogicaldisk' 'SNMP QNAP Physikalischer Datenträger' = 'snmpqnapphysicaldisk' 'SNMP QNAP Systemzustand' = 'snmpqnapsystemhealth' 'SNMP RMON' = 'snmprmon' 'SNMP-Datenverkehr' = 'snmptraffic' 'SNMP-Laufzeit' = 'snmpuptime' 'SNTP' = 'sntp' 'SSL-Sicherheitsüberprüfung' = 'ssl' 'SSL-Zertifikatssensor' = 'sslcertificate' 'Systemzustand' = 'systemstate' 'SNMP-Trap-Empfänger' = 'udptrap' 'VMware Virtual Machine (SOAP)' = 'vcenterserverextern' 'VMware Datastore (SOAP)' = 'vmwaredatastoreextern' 'Ereignisprotokoll (Windows API)' = 'winapieventlog' 'WMI Sicherheits-Center' = 'wmiantivirus' 'WMI Laufwerkskapazität (mehrf.)' = 'wmidiskspace' 'WMI Ereignisprotokoll' = 'wmieventlog' 'WMI Exchange Transportwarteschlange' = 'wmiexchangetransportqueues' 'Hyper-V Virtuelle Maschine' = 'wmihyperv' 'Hyper-V Host Server' = 'wmihypervserver' 'Hyper-V Virtuelles Speichergerät' = 'wmihypervvirtualstoragedevice' 'Windows IIS-Anwendung' = 'wmiiis' 'WMI Logischer Datenträger E/A BETA' = 'wmilogicaldiskv2' 'WMI Arbeitsspeicher' = 'wmimemory' 'WMI Netzwerkadapter' = 'wminetwork' 'WMI Auslagerungsdatei' = 'wmipagefile' 'Windows Physikalischer Datenträger E/A BETA' = 'wmiphysicaldiskv2' 'Windows Prozess' = 'wmiprocess' 'Windows Prozessorlast' = 'wmiprocessor' 'WMI Dienst' = 'wmiservice' 'WMI Freigabe' = 'wmishare' 'WMI Microsoft SQL Server 2012' = 'wmisqlserver2012' 'WMI Terminaldienste (Windows 2008+)' = 'wmiterminalservices2008' 'Windows Systemlaufzeit' = 'wmiuptime' 'WMI UTC-Zeit' = 'wmiutctime' 'WMI Wichtige Systemdaten (v2)' = 'wmivitalsystemdata' 'WMI Datenträger' = 'wmivolume' } #> } process { switch ($PsCmdlet.ParameterSetName) { 'ByTAGName' { if ($CaseSensitive -and (-not $IncludeInherited)) { foreach ($TagName in $ByTAGName) { Write-Log -LogText "Search casesensitive only in 'tags'-property for $TagName in SensorTree" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput New-Variable -Name result -Force -Confirm:$false -Debug:$false -Verbose:$false -WhatIf:$false $result = $SensorTree.SelectNodes("/prtg/sensortree/nodes/group//*[contains(tags,'$($TagName.Replace('*',''))')]") Set-TypesNamesToPRTGObject -PRTGObject $result } } else { Write-Log -LogText "Search method: caseinsensitive" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput New-Variable -Name objects -Force -Confirm:$false -Debug:$false -Verbose:$false -WhatIf:$false $Objects = Get-PRTGObject -SensorTree $SensorTree -Verbose:$false foreach ($Object in $Objects) { foreach ($TagName in $ByTAGName) { if ($IncludeInherited) { Write-Log -LogText "Search caseinsensitive for $TagName in 'tagsAll'-property" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput if ($Object.tagsAll) { if ($Object.tagsAll.split(' ') -like $TagName) { $Object } } } else { Write-Log -LogText "Search caseinsensitive for $TagName in 'tags'-property" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput if ($Object.tags) { if ($Object.tags.split(' ') -like $TagName) { $Object } } } } } } } 'ByStatus' { foreach ($Status in $ByStatus) { Write-Log -LogText "Searching for objects by staus $Status" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput New-Variable -Name result -Force -Confirm:$false -Debug:$false -Verbose:$false -WhatIf:$false $result = $SensorTree.SelectNodes("/prtg/sensortree/nodes/group//*[status_raw=$($StatusMapping."$Status")]") Set-TypesNamesToPRTGObject -PRTGObject $result } } 'BySensorType' { foreach ($SensorType in $BySensorType) { Write-Log -LogText "Searching for objects by type $SensorType" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput New-Variable -Name result -Force -Confirm:$false -Debug:$false -Verbose:$false -WhatIf:$false $result = $SensorTree.SelectNodes("/prtg/sensortree/nodes/group//*[sensortype='$("$SensorType")']") Set-TypesNamesToPRTGObject -PRTGObject $result } } } } end {} } function Get-PRTGObject { <# .Synopsis Get-PRTGObject .DESCRIPTION Returns one more multiple types of objects from sensortree .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Get-PRTGObject Query all objects from the default sensortree (global variable after connect to PRTG server) .EXAMPLE Get-PRTGObject -SensorTree $SensorTree Query objects by name from a non default sensortree .EXAMPLE Get-PRTGObject -Name "Object01" Query objects by name .EXAMPLE Get-PRTGObject -Name "Object01", "Object*" -Recursive Query objects by name with all subobjects .EXAMPLE Get-PRTGObject -Name "Object01", "Object*" -Type 'probenode', 'group', 'device', 'sensor' Query only selected type of objects by name .EXAMPLE PS C:\>Get-PRTGObject -Name "Object01", "Object*" -Type 'probenode', 'group', 'device', 'sensor' -Recursive Query only selected type of objects by name with all subobjects PS C:\>Get-PRTGObject -Name "Object01", "Object*" -SensorTree $SensorTree Query objects by name from a non default sensortree PS C:\>"Object01" | PRTGObject Piping is also possible .EXAMPLE PS C:\>Get-PRTGObject -ObjectID 1 Query objects by object ID PS C:\>Get-PRTGObject -ObjID 1 , 100 PS C:\>Get-PRTGObject -ID 1, 100 all the parameter combination from the example above are also possible PS C:\>1 | Get-PRTGObject Piping is also possible .EXAMPLE PS C:\>Get-PRTGObject -FilterXPath "/prtg/sensortree/nodes/group//*[id='1']" for people who know what they do... :-) query objects directly by XPatch filter string PS C:\>Get-PRTGObject -FilterXPath "/prtg/sensortree/nodes/group//probenode" -SensorTree $SensorTree #> [CmdletBinding( DefaultParameterSetName = 'ReturnAll', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( # ID of the PRTG object [Parameter(ParameterSetName = 'ID', Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = 'ReturnAll', Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('objID', 'ID')] [int[]] $ObjectID, # The name of the object [Parameter(ParameterSetName = 'Name', Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [String[]] $Name, # The fullname of the object [Parameter(ParameterSetName = 'FullName', Position = 0, Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [String[]] $FullName, # XPath filter expression for advanced usage [Parameter(ParameterSetName = 'XPath', Position = 0, Mandatory = $true)] [String[]] $FilterXPath, # Filter of types [Parameter(ParameterSetName = 'ReturnAll')] [Parameter(ParameterSetName = 'ID')] [Parameter(ParameterSetName = 'Name')] [Parameter(ParameterSetName = 'FullName')] [ValidateSet('group', 'device', 'sensor', 'probenode')] [ValidateNotNullOrEmpty()] [string[]] $Type = ('group', 'device', 'sensor', 'probenode'), # Parse recursivly through the groups [Parameter(ParameterSetName = 'ReturnAll')] [Parameter(ParameterSetName = 'ID')] [Parameter(ParameterSetName = 'Name')] [Parameter(ParameterSetName = 'FullName')] [switch] $Recursive, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) Begin {} Process { [Array]$result = @() switch ($PsCmdlet.ParameterSetName) { 'ID' { $ParameterSet = 'ID' } 'Name' { $ParameterSet = 'Name' } 'Fullname' { $ParameterSet = 'Fullname' } 'XPath' { $ParameterSet = 'XPath' } { $_ -eq 'ReturnAll' -and $ObjectID } { $ParameterSet = 'ID' } Default { $ParameterSet = 'ReturnAll' } } #Write-Host "$ParameterSet - $ObjectID" -ForegroundColor Green switch ($ParameterSet) { 'ID' { foreach ($ID in $ObjectId) { Write-Log -LogText "Query logic is:$($ParameterSet). Going to find the object by ID $($ID) value." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput [string]$BasePath = "/prtg/sensortree/nodes/group//*[id=$($ID)]" $SeachString = $BasePath if ($Recursive) { foreach ($item in $Type) { Write-Log -LogText "Recursice switch detected. Compiling recursive searchstring for $($item)s unter object $ID" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $SeachString = $SeachString + ' | ' + $BasePath + "//" + $item } } Write-Log -LogText "Searchstring for query on sensortree: $SeachString." -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $result += $SensorTree.SelectNodes($SeachString) if ($type.count -lt 4) { $result = $result | Where-Object LocalName -In $type } Write-Log -LogText "Found $($result.Count) $([string]::Join('s,',$Type))s in sensortree." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput Remove-Variable item, SeachString, BasePath -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false } } 'Name' { foreach ($NameItem in $Name) { Write-Log -LogText "Query logic is:$($ParameterSet). Going to find the object by Name ""$($Name)"" value." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput #assume find object directly no filtering after xpath needed $FilterAfterQuery = $false [string]$BasePath = "/prtg/sensortree/nodes/group//*[name='$($NameItem)']" if ($NameItem.contains('*') -and $NameItem.StartsWith('*') -and $NameItem.EndsWith('*') -and (-not $NameItem.Trim('*').contains('*'))) { #$NameItem is something like "*machine*" -> xpath with "contains" can be used, no filtering after xpath needed [string]$BasePath = "/prtg/sensortree/nodes/group//*[contains(name,'$($NameItem.Replace('*',''))')]" } elseif ($NameItem.contains('*')) { #$NameItem is something like "*machine*01*" or "machine*01" -> filter after xpath is needed [string]$BasePath = '/prtg/sensortree/nodes/group' $FilterAfterQuery = $true Write-Log -LogText "Switch on FilterAfterQuery" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput } $SeachString = $BasePath if ($Recursive -or $FilterAfterQuery) { foreach ($item in $Type) { Write-Log -LogText "Recursice switch detected. Compiling recursive searchstring for $($item)s." -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $SeachString = $SeachString + ' | ' + $BasePath + "//" + $item } } Write-Log -LogText "Searchstring for query on sensortree: $SeachString." -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput if ($FilterAfterQuery -and (-not $Recursive)) { $result += $SensorTree.SelectNodes($SeachString) | Where-Object Name -Like $NameItem } elseif ($FilterAfterQuery -and $Recursive) { $group = $SensorTree.SelectNodes($SeachString) | Where-Object Name -Like $NameItem | Group-Object type $subResult = @() foreach ($g in $group) { switch ($g.name) { 'sensor' { $result += $g.group } Default { [int]$i = 0 [int]$iComplete = $g.Group.count foreach ($h in $g.Group) { $i++ Write-Progress -Activity "Recursive filtering..." -PercentComplete ($i / $iComplete * 100) $subResult += Get-PRTGObject -ObjectID $h.ObjID -Recursive -SensorTree $SensorTree -Verbose:$false } } } } $result += $subResult } else { $result += $SensorTree.SelectNodes($SeachString) } if ($Type.count -lt 4) { $result = $result | Where-Object LocalName -in $Type } Write-Log -LogText "Found $($result.Count) $([string]::Join('s,',$Type))s in sensortree." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput Remove-Variable item, SeachString, BasePath -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false } } 'Fullname' { foreach ($FullnameItem in $Fullname) { if ($Recursive) { $FullnameItem = "*$FullnameItem*" } Write-Log -LogText "Query logic is:$($ParameterSet). Going to find the object by FullName ""$($FullnameItem)"" value." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput [string]$BasePath = '/prtg/sensortree/nodes/group' $Count = 0 foreach ($item in $Type) { Write-Log -LogText "Compiling searchstring for $item" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput if ($Count -eq 0) { $SeachString = $BasePath + "//" + $item } else { $SeachString = $SeachString + ' | ' + $BasePath + "//" + $item } $count ++ } Write-Log -LogText "Final Searchstring for sensortree: $SeachString" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $objects = $SensorTree.SelectNodes($SeachString) $objectsCollection = foreach ($item in $objects) { $item.pstypenames.Insert(0, "PRTG.Object") $item.pstypenames.Insert(1, "PRTG") $item } Remove-Variable item -Force -ErrorAction Ignore foreach ($search in $FullnameItem) { $result += $objectsCollection | Where-Object fullname -Like $search } Write-Log -LogText "Found $($result.Count) $([string]::Join('s,',$Type))s in sensortree." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput Remove-Variable Count, item, SeachString, BasePath -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false } } 'XPath' { foreach ($XPath in $FilterXPath) { Write-Log -LogText "Query logic is:$($ParameterSet). Returning all objects with filterstring: ""$($XPath)""" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $result = $SensorTree.SelectNodes($XPath) Write-Log -LogText "Found $($result.Count) objects in sensortree." -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput } } Default { Write-Log -LogText "Query logic is:$($ParameterSet). Returning all objects" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput [string]$BasePath = '/prtg/sensortree/nodes/group' $Count = 0 foreach ($item in $Type) { Write-Log -LogText "Compiling searchstring for $item" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput if ($Count -eq 0) { $SeachString = $BasePath + "//" + $item } else { $SeachString = $SeachString + ' | ' + $BasePath + "//" + $item } $count ++ } Write-Log -LogText "Final Searchstring for sensortree: $SeachString." -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $result = $SensorTree.SelectNodes($SeachString) Write-Log -LogText "Found $($result.Count) $([string]::Join(',',$Type)) in sensortree." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput Remove-Variable Count, item, SeachString, BasePath -Force -ErrorAction Ignore -Verbose:$false -Debug:$false -WhatIf:$false } } if ($result) { if ($PsCmdlet.ParameterSetName -ne 'ReturnAll' -and $Type.count -gt 1) { $result = $result | select-object * -Unique } Set-TypesNamesToPRTGObject -PRTGObject $result } else { Write-Log -LogText "Error query object by $($PsCmdlet.ParameterSetName). No object found!" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error } } End {} } function Get-PRTGObjectProperty { <# .Synopsis Get-PRTGObjectProperty .DESCRIPTION Get a specific property from an PRTG object out of the sensor tree .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Get-PRTGObjectProperty -ObjectId 1 -PropertyName Name, tags Get name and tags from object with ID 1 .EXAMPLE Get-PRTGObject -Name "Myobject" | Get-PRTGObjectProperty -Name Name, status Get name and status from object "Myobject" #> [CmdletBinding( DefaultParameterSetName = 'ReturnAll', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] [OutputType([PSCustomObject])] Param( # ID of the object to pause/resume [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript({ $_ -gt 0 })] [Alias('objID', 'ID')] [int[]] $ObjectID, # Name of the object's property to get [Parameter(Position = 1, ParameterSetName = 'Name')] [Alias('Name')] [ValidateNotNullOrEmpty()] [string[]] $PropertyName, # SensorTree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) Begin {} Process { foreach ($ID in $ObjectID) { Write-Log -LogText "Get object details from object ID $ID." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput try { $Object = Get-PRTGObject -ID $ID -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop } catch { Write-Log -LogText $_.exception.message -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error return } $ObjectProperty = $Object | Get-Member -MemberType Property, NoteProperty | Select-Object -ExpandProperty Name $hash = @{} if ($PropertyName) { # Parameterset: Name foreach ($item in $PropertyName) { $PropertiesToQuery = $ObjectProperty | Where-Object { $_ -like $item } foreach ($PropertyItem in $PropertiesToQuery) { if ($hash.$PropertyItem) { Write-Log -LogText "Property $PropertyItem already existis! Skipping this one." -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput } else { Write-Log -LogText "Get property $PropertyItem from object ID $ID" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $hash.Add($PropertyItem, $object.$PropertyItem) } } } $result = New-Object -TypeName PSCustomObject -Property $hash } else { #Parameterset: ReturnAll Write-Log -LogText "Get all properties from object ID $ID" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput foreach ($PropertyItem in $ObjectProperty) { $hash.Add($PropertyItem, $object.$PropertyItem) } } $result = New-Object -TypeName PSCustomObject -Property $hash Write-Log -LogText "Found $($result.count) $(if($result.count -eq 1){"property"}else{"properties"}) in object ID $ID" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $result } } End {} } function Get-PRTGObjectTAG { <# .Synopsis Get-PRTGObjectTAG .DESCRIPTION Get the tags property from an PRTG object out of the sensor tree and returns a string array .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Get-PRTGObjectTAG -ObjectId 1 Get ObjectTags from object with ID 1 #> [CmdletBinding( DefaultParameterSetName = 'ReturnAll', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] [OutputType( [String[]] )] Param( # ID of the object to pause/resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('objID', 'ID')] [int] $ObjectID, # SensorTree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin {} process { #Get the object Write-Log -LogText "Get object tags from object ID $ObjectID." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput try { $Object = Get-PRTGObject -ID $ObjectID -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop } catch { Write-Log -LogText $_.exception.message -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error return } if ($Object.tags) { [Array]$result = $Object.tags.Split(' ') } else { Write-Log -LogText "No tags in object ""$($Object.name)"" (ID:$($ObjectID))" -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Warning return } Write-Log -LogText "Found $($result.count) $(if($result.count -eq 1){"tag"}else{"tags"}) in object ID $ObjectID" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $result } end {} } function Invoke-PRTGObjectRefresh { <# .Synopsis Invoke-PRTGObjectRefresh .DESCRIPTION Enables an (paused) PRTG object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Invoke-PRTGObjectRefresh -ObjectId 1 Refreshes objct with ID 1 #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] Param( # ID of the object to resume [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if (($_.StartsWith("http"))) {$true} else {$false} } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass ) Begin { $body = @{ id = 0 username = $User passhash = $Pass } } Process { foreach ($id in $ObjectId) { $body.id = $id if ($pscmdlet.ShouldProcess("objID $Id", "Call scan now procedure on object")) { try { Write-Log -LogText "Call scan now procedure on object ID $id ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $null = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/scannow.htm" -Method Get -Body $Body -Verbose:$false -Debug:$false -ErrorAction Stop } catch { Write-Log -LogText "Failed to Call scan now procedure on object ID $id. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error } } } } End {} } function Move-PRTGObjectPosition { <# .Synopsis Move-PRTGObjectPosition .DESCRIPTION Moves an object in PRTG hierarchy .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Move-PRTGObject -ObjectId 1 -Direction up Move object with ID 1 one position up inside the group/structure #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] Param( # ID of the object to resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # Message to associate with the pause event [Parameter(Mandatory = $true)] [ValidateSet("up", "down", "top", "bottom")] [string] $Direction, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass ) begin {} process { foreach ($id in $ObjectId) { $body = @{ id = $id newpos = $Direction username = $User passhash = $Pass } if ($pscmdlet.ShouldProcess("objID $Id", "Move $Direction")) { try { Write-Log -LogText "Move object ID $id $Direction ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $null = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/setposition.htm" -Method Get -Body $Body -Verbose:$false -Debug:$false -ErrorAction Stop } catch { Write-Log -LogText "Failed to move object ID $id. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error } } } } end {} } function Receive-PRTGObject { <# .Synopsis Receive-PRTGObject .DESCRIPTION Query an object directly from PRTGserver and returns. Difference to Get-PRTGObject is, that "Get-PRTGObject" is working on a modfified sensortree variable in the memory and not on livedata from PRTGServer .NOTES Author: Andreas Bellstedt adopted from PSGallery Module "PSPRTG" Author: Sam-Martin Github: https://github.com/Sam-Martin/prtg-powershell .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE PS C:\>Receive-PRTGObject Receive devices live from PRTG server (not using the cached sensor tree info) .EXAMPLE PS C:\>Receive-PRTGObject -Content sensors Receive sensors live from PRTG server (not using the cached sensor tree info) #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $false, ConfirmImpact = 'low' )] Param( # Number of maximal results [int] $NumResults = 99999, # Properties to query [string] $Columns = "objid,type,name,tags,active,host", # Type of device to query [ValidateSet("sensortree", "groups", "sensors", "devices", "tickets", "messages", "values", "channels", "reports", "storedreports", "ticketdata")] [string] $Content = "devices", # sorting the output [string] $SortBy = "objid", # Direction to sort the output [ValidateSet("Desc", "Asc")] [string] $SortDirection = "Desc", # Filter hashtable to filter out objects from the query [hashtable] $Filters, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass ) $SortDirectionPRTGStyle = if ($SortDirection -eq "Desc") { "-" }else { '' } $body = @{ content = $content; count = $numResults; output = "xml"; columns = $columns; sortby = "$SortDirectionPRTGStyle$SortBy"; username = $User passhash = $Pass } foreach ($FilterName in $Filters.keys) { $body.Add($FilterName, $Filters.$FilterName) } # Try to get the PRTG device tree try { $prtgDeviceTree = Invoke-RestMethod -UseBasicParsing -Uri "$Server/api/table.xml" -Method Get -Body $Body -Verbose:$false -Debug:$false -ErrorAction Stop } catch { Write-Log -LogText "Failed to get PRTG Device tree $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error return } $prtgDeviceTree } function Receive-PRTGObjectDetail { <# .Synopsis Receive-PRTGObjectDetail .DESCRIPTION Query status information for an object directly from PRTGserver. (function not working on sensortree variable in memory) .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE PS C:\>Receive-PRTGObjectDetail -ObjectId 1 PS C:\>Receive-PRTGObjectDetail -ID 1 Query object details of object 1 live from PRTG server. (not using the value in the sensor tree) .EXAMPLE PS C:\>Receive-PRTGObjectDetail -ObjectId 1 -Server "https://prtg.corp.customer.com" -User "admin" -Pass "1111111" Query object details of object 1 live from PRTG server. (not using the value in the sensor tree) #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $false, ConfirmImpact = 'low' )] param( # ID of the object to pause/resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('ObjId', 'ID')] [int] $ObjectId, # Name of the object's property to get [ValidateNotNullOrEmpty()] [string] $PropertyName, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass ) Begin { $body = @{ id = 0 username = $User passhash = $Pass } } Process { foreach ($ID in $ObjectID) { $body.id = $ID Write-Log -LogText "Get details for object ID $ID. ($Server)" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput try { $Object = (Invoke-RestMethod -Uri "$Server/api/getsensordetails.xml" -Method Get -Body $Body -Verbose:$false -Debug:$false -ErrorAction Stop).sensordata } catch { Write-Log -LogText "Failed to get details for object from prtg. ($Server) Message:$($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error } $ObjectProperty = $Object | Get-Member -MemberType Property | Select-Object -ExpandProperty Name $hash = @{} if ($PropertyName) { #Parameterset: Name foreach ($item in $PropertyName) { $PropertiesToQuery = $ObjectProperty | Where-Object { $_ -like $item } foreach ($PropertyItem in $PropertiesToQuery) { if ($hash.$PropertyItem) { Write-Log -LogText "Property $PropertyItem already existis! Skipping this one." -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput } else { Write-Log -LogText "Get property $PropertyItem from object ID $ID" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $hash.Add($PropertyItem, $object.$PropertyItem) } } } $result = New-Object -TypeName PSCustomObject -Property $hash } else { #Parameterset: ReturnAll Write-Log -LogText "Get all properties from object ID $ID" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput foreach ($PropertyItem in $ObjectProperty) { $hash.Add($PropertyItem, $object.$PropertyItem.'#cdata-section') } } $result = New-Object -TypeName PSCustomObject -Property $hash Write-Log -LogText "Found $($result.count) $(if($result.count -eq 1){"property"}else{"properties"}) in object ID $ID" -LogType Info -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $result } } } function Receive-PRTGObjectProperty { <# .Synopsis Receive-PRTGObject .DESCRIPTION Query an object property directly from PRTGserver and returns. Difference to Get-PRTGObjectProperty is, that "Get-PRTGObjectProperty" is working on a modfified sensortree variable in the memory and not on livedata from PRTGServer .NOTES Author: Andreas Bellstedt adopted from PSGallery Module "PSPRTG" Author: Sam-Martin Github: https://github.com/Sam-Martin/prtg-powershell .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE PS C:\>Receive-PRTGObject -ObjectId 1 -PropertyName "staus" PS C:\>Receive-PRTGObject -ID 1 -Name "staus" Query property of object 1 live from PRTG server. (not using the value in the sensor tree) .EXAMPLE PS C:\>Receive-PRTGObject -ObjectId 1 -PropertyName "staus" -Server "https://prtg.corp.customer.com" -User "admin" -Pass "1111111" Query property of object 1 live from PRTG server. (not using the value in the sensor tree) #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $false, ConfirmImpact = 'low' )] param( # ID of the object to pause/resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('ObjId', 'ID')] [int[]] $ObjectId, # Name of the object's property to get [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [Alias('Name')] [string] $PropertyName, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass ) Begin { $body = @{ id = 0 name = $PropertyName username = $User passhash = $Pass } } Process { foreach ($ID in $ObjectID) { $body.id = $ID # Try to get objectproperty from PRTG Write-Log -LogText "Get objectproperty for object ID $ID. ($Server)" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput try { $Result = (Invoke-RestMethod -UseBasicParsing -Uri "$Server/api/getobjectstatus.htm" -Method Get -Body $Body -Verbose:$false -Debug:$false -ErrorAction Stop).prtg.result return $result } catch { Write-Log -LogText "Failed to get objectproperty from prtg. ($Server) Message:$($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error } } } End { } } Function Receive-PRTGObjectStatus { <# .Synopsis Receive-PRTGObjectStatus .DESCRIPTION Query the status of an object directly from PRTGserver and returns. Difference to Get-PRTGObject is, that "Get-PRTGObject" is working on a modfified sensortree variable in the memory and not on livedata from PRTGServer .NOTES Author: Andreas Bellstedt adopted from PSGallery Module "PSPRTG" Author: Sam-Martin Github: https://github.com/Sam-Martin/prtg-powershell .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE PS C:\>Receive-PRTGObjectStatus -ObjectId 1 PS C:\>Receive-PRTGObjectStatus -ID 1 Query current status of object 1 live from PRTG server. (not using the value in the sensor tree) .EXAMPLE PS C:\>Receive-PRTGObjectStatus -ObjectId 1 -Server "https://prtg.corp.customer.com" -User "admin" -Pass "1111111" Query current status of object 1 live from PRTG server. (not using the value in the sensor tree) #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $false, ConfirmImpact = 'low' )] [OutputType([PSCustomObject])] Param( # ID of the object to pause/resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('ID')] [ValidateScript( { $_ -gt 0 })] [int[]] $ObjectID, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass ) Begin { $StatusMapping = @{ 1 = "Unknown" 2 = "Scanning" 3 = "Up" 4 = "Warning" 5 = "Down" 6 = "No Probe" 7 = "Paused by User" 8 = "Paused by Dependency" 9 = "Paused by Schedule" 10 = "Unusual" 11 = "Not Licensed" 12 = "Paused Until" } } Process { foreach ($ID in $ObjectId) { try { $statusID = (Receive-PRTGObjectProperty -ObjectId $ID -PropertyName 'status' -Server $Server -User $User -Pass $Pass -ErrorAction Stop -Verbose:$false) } catch { Write-Log -LogText "Unable to get object status from prtg. ($Server) Message:$($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error return } $hash = @{ 'objid' = $ID "status" = $StatusMapping[[int]$statusID] "status_raw" = $statusID } $result = New-Object -TypeName PSCustomObject -Property $hash $result } } end {} } function Remove-PRTGObject { <# .Synopsis Remove-PRTGObject .DESCRIPTION Remove an object from PRTGserver and returns. Difference to Get-PRTGObject is, that "Get-PRTGObject" is working on a modfified sensortree variable in the memory and not on livedata from PRTGServer .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt adopted from PSGallery Module "PSPRTG" Author: Sam-Martin Github: https://github.com/Sam-Martin/prtg-powershell .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE PS C:\>Remove-PRTGObject -ObjectId 1 Remove object with ID 1 .EXAMPLE PS C:\>Get-PRTGObject -ObjectId 1 | Remove-PRTGObject Remove object with ID 1 #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'high' )] [OutputType([Boolean])] Param( # ID of the object to delete [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('objID', 'ID')] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [int[]] $ObjectID, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree, # returns the deleted object [Switch] $PassThru ) Begin {} Process { $Deleted = @() foreach ($ID in $ObjectID) { $body = @{ id = $ID approve = 1 username = $User passhash = $Pass } # Check for object on sensor tree try { $Object = Get-PRTGObject -ObjectID $id -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop } catch { Write-Log -LogText "Cannot find object ID $ID" -LogType Error -LogScope $MyInvocation.MyCommand.Name -Error -NoFileStatus break } if ($pscmdlet.ShouldProcess("$($Object.name) objID $ID", "Remove PRTG object")) { #Remove in PRTG try { Write-Log -LogText "Remove object ID $ID ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $Result = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/deleteobject.htm " -Method Get -Body $Body -Verbose:$false -Debug:$false -ErrorAction Stop } catch { Write-Log -LogText "Failed to delete object $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -Error -NoFileStatus break } #Remove on SensorTree if ($Result.StatusCode -eq 200) { $ToDelete = $SensorTree.SelectSingleNode("//*[id='$ID']") while ($ToDelete -ne $null) { $Deleted = $ToDelete.ParentNode.RemoveChild($ToDelete) $ToDelete = $SensorTree.SelectSingleNode("//*[id='$ID']") } Write-Log -LogText "Remove object ID $($ID) with name ""$($Deleted.name)"". ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput } else { Write-Log -LogText "Failed to delete object ID $($Deleted.ObjID). ($($Server)) Message:$($Result.StatusCode) $($Result.StatusDescription)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error break } #Write-Uutput if ($PassThru) { Set-TypesNamesToPRTGObject -PRTGObject $Deleted } } } } End {} } function Remove-PRTGObjectTAG { <# .Synopsis Remove-PRTGObjectTAG .DESCRIPTION Remove a text from the tags property of an PRTG object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE PS C:\>Remove-PRTGObjectTAG -ObjectId 1 -TAGName "MyTAG" Remove "MyTAG" from an object with ID 1 #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] Param( # ID of the object to pause/resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('ObjID', 'ID')] [int] $ObjectId, # Name of the object's property to set [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $false)] [ValidateNotNullOrEmpty()] [string[]] $TAGName, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree, # Skip errors if an tag is not present [Switch] $Force, # Output the deleted object [Switch] $PassThru ) Begin {} Process { foreach ($ID in $ObjectId) { $break = $false #Get the object Write-Log -LogText "Gather object tags from object ID $ID." -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput try { $Object = Get-PRTGObject -ID $ID -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop } catch { Write-Log -LogText $_.exception.message -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error return } #Build and check TAG lists $TAGListExisting = $Object.tags.Split(' ') $TAGListToSet = $Object.tags $TAGListCount = 0 foreach ($TAG in $TAGName) { if ($TAG -in $TAGListExisting) { $TAGListToSet = $TAGListToSet -replace [regex]::Escape($TAG), '' $TAGListCount++ } else { if ($Force) { Write-Log -LogText "Skipping tag ""$($TAG)"", because it is not present on object id $ID" -LogType Warning -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Warning } else { Write-Log -LogText "Tag ""$($TAG)"" is not present on object id $ID" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error $break = $true break } } } $TAGListToSet = $TAGListToSet.Trim() if ($break) { break } #set TAG list to PRTG object $MessageText = "Remove $($TAGListCount) $(if($TAGListCount -eq 1) {"tag"} else {"tags"})" if ($pscmdlet.ShouldProcess("objID $ID", $MessageText)) { Write-Log -LogText $MessageText -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput try { #Set in PRTG Set-PRTGObjectProperty -ObjectId $ID -PropertyName tags -PropertyValue $TAGListToSet -Server $Server -User $User -Pass $Pass -ErrorAction Stop -Verbose:$false #Set on object to return $Object.tags = $TAGListToSet #Set in SensorTree variable $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($ID)]/tags").InnerText = $TAGListToSet } catch { Write-Log -LogText $_.exception.message -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error if (-not $Force) { break } } } #output the object if ($PassThru) { $Object } #clear up the variable mess Remove-Variable TAG, TAGListExisting, TAGListToSet, Object, MessageText -Force -ErrorAction Ignore -Confirm:$false -Verbose:$false -Debug:$false -WhatIf:$false } } End {} } function Rename-PRTGObject { <# .Synopsis Rename-PRTGObject .DESCRIPTION Rename an PRTG object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt adopted from PSGallery Module "PSPRTG" Author: Sam-Martin Github: https://github.com/Sam-Martin/prtg-powershell .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Rename-PRTGObject -ObjectId 1 -NewName "NewName" Rename object with ID 1 to "NewName" .EXAMPLE Get-PRTGObject "MyDevice" | Rename-PRTGObject -NewName "MyNewDevice" Rename "MyDevice" to "MyNewDevice" #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] Param( # ID of the object to pause/resume [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [int] $ObjectId, # New name of the object [string] $NewName, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # SensorTree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) $body = @{ id = $ObjectId value = $NewName username = $User passhash = $Pass } Write-Log -LogText "Get object details from object ID $ObjectId. ($Server)" -LogType Query -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput try { $object = Get-PRTGObject -ID $ObjectId -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop } catch { Write-Log -LogText $_.exception.message -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error return } if ($pscmdlet.ShouldProcess("objID $ObjectId", "Rename PRTG object to '$NewName'")) { # Set in PRTG try { Write-Log -LogText "Set new name ""$($NewName)"" on object ID $ObjectId. ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $null = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/rename.htm" -Method Get -Body $body -Verbose:$false } catch { Write-Log -LogText "Failed to rename object ID $ObjectId. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error return } # Set on SensorTree variable $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($ObjectId)]/name").InnerText = $object.Name # Write output Get-PRTGObject -ID $ObjectId -SensorTree $SensorTree -Verbose:$false -ErrorAction Stop } } function Set-PRTGObjectAlarmAcknowledgement { <# .Synopsis Set-PRTGObjectAlarmAcknowledgement .DESCRIPTION Acknowledge an alarm on a PRTG object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Set-PRTGObjectAlarmAcknowledgement -ObjectId 1 Set alarm on object 1 .EXAMPLE Set-PRTGObjectAlarmAcknowledgement -ObjectId 1 -Message "Done by User01" Set alarm on object 1 with indidual message #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] [Alias('Set-PRTGObjectAlamAcknowledgement')] # in because of typo in cmdletname in previous version, not to produce a breaking change with the typo fix Param( # ID of the object to resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # Message to associate with the pause event] [string] $Message, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass ) Begin {} Process { foreach ($id in $ObjectId) { $body = @{ id = $id username = $User passhash = $Pass } if ($Message) { $body.Add("ackmsg", $Message) } if ($pscmdlet.ShouldProcess("objID $Id", "Acknowledge alarm on object")) { try { Write-Log -LogText "Acknowledge alarm on object ID $id ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $null = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/acknowledgealarm.htm" -Method Get -Body $Body -Verbose:$false -Debug:$false -ErrorAction Stop } catch { Write-Log -LogText "Failed to acknowledge alarm on object ID $id. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error } } } } End {} } function Set-PRTGObjectPriority { <# .Synopsis Set-PRTGObjectPriority .DESCRIPTION Set priority value on a PRTG object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Set-PRTGObjectPriority -ObjectId 1 -Priority 3 Set priority on object 1 .EXAMPLE Set-PRTGObjectPriority -ObjectId 1 -Priority 3 -PassThru Set priority on object 1 and output the object .EXAMPLE Set-PRTGObjectPriority -ObjectId 1 -Priority 3 -Server "https://prtg.corp.customer.com" -User "admin -Pass "1111111" Set priority on object 1 on explicitly specified server with custom credentials. #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] Param( # ID of the object to resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # Priority value to set [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidatePattern("[1-5]")] [int] $Priority, # returns the changed object [Switch] $PassThru, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) Begin {} Process { foreach ($id in $ObjectId) { $body = @{ id = $id prio = $Priority username = $User passhash = $Pass } if ($pscmdlet.ShouldProcess("objID $Id", "Set priority $Priority to object")) { #Set in PRTG try { Write-Log -LogText "Set priority $Priority to object ID $id ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $null = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/setpriority.htm" -Method Get -Body $Body -Verbose:$false -Debug:$false -ErrorAction Stop } catch { Write-Log -LogText "Failed to set priortiy object ID $id. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error } #Set on SensorTree Variable $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($ID)]/priority").InnerText = $Priority #Write-Output if ($PassThru) { Get-PRTGObject -ObjectID $id -SensorTree $SensorTree -Verbose:$false } } } } End {} } function Set-PRTGObjectProperty { <# .Synopsis Set-PRTGObjectProperty .DESCRIPTION Set the property of an PRTG object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt adopted from PSGallery Module "PSPRTG" Author: Sam-Martin Github: https://github.com/Sam-Martin/prtg-powershell .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Set-PRTGObjectProperty -ObjectId 1 -PropertyName "Name" -PropertyValue "NewValue" Set object property in PRTG .EXAMPLE Set-PRTGObjectProperty -ObjectId 1 -PropertyName "Name" -PropertyValue "NewValue" -Server "https://prtg.corp.customer.com" -User "admin -Pass "1111111" Set object property in PRTG #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] Param( # ID of the object to pause/resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -ge 0 } )] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # Name of the object's property to set [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $PropertyName, # Value to which to set the property of the object [string] $PropertyValue, # returns the changed object [Switch] $PassThru, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) Begin {} Process { foreach ($id in $ObjectId) { $body = @{ id = $id action = 1 name = $PropertyName value = $PropertyValue username = $User passhash = $Pass } if ($pscmdlet.ShouldProcess("objID $Id", "Set property '$PropertyName' to '$PropertyValue' on PRTG object")) { # Set property in PRTG try { Write-Log -LogText "Set property ""$PropertyName"" to ""$PropertyValue"" on object ID $id ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $null = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/setobjectproperty.htm" -Method Get -Body $body -Verbose:$false } catch { Write-Log -LogText "Failed to set value $PropertyValue on property $PropertyName. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -Error -NoFileStatus } # Set property in SensorTree Variable if ($PropertyName -eq "id") { $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($id)]").SetAttribute($PropertyName, $PropertyValue) } $SensorTree.SelectSingleNode("/prtg/sensortree/nodes/group//*[id=$($id)]/$PropertyName").InnerText = $PropertyValue # Write-Output if ($PassThru) { Get-PRTGObject -ObjectID $id -SensorTree $SensorTree -Verbose:$false } } } } End {} } function Test-PRTGObjectNotification { <# .Synopsis Test-PRTGObjectNotification .DESCRIPTION Test a notifcation action for a object .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Test-PRTGObjectNotification -ObjectId 1 Test a notifcation action for object with ID 1 #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, ConfirmImpact = 'medium' )] Param( # ID of the object to resume [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 } )] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # Url for PRTG Server [ValidateNotNullOrEmpty()] [ValidateScript( { if ($_.StartsWith("http")) { $true } else { $false } } )] [String] $Server = $script:PRTGServer, # User for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $User = $script:PRTGUser, # Password or PassHash for PRTG Authentication [ValidateNotNullOrEmpty()] [String] $Pass = $script:PRTGPass ) Begin {} Process { foreach ($id in $ObjectId) { $body = @{ id = $id username = $User passhash = $Pass } if ($pscmdlet.ShouldProcess("objID $Id", "Test notification for object")) { try { Write-Log -LogText "Test notification for object ID $id ($Server)" -LogType Set -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -DebugOutput $null = Invoke-WebRequest -UseBasicParsing -Uri "$Server/api/notificationtest.htm" -Method Get -Body $Body -Verbose:$false -Debug:$false -ErrorAction Stop } catch { Write-Log -LogText "Failed to test notification for object ID $id. $($_.exception.message)" -LogType Error -LogScope $MyInvocation.MyCommand.Name -NoFileStatus -Error } } } } End {} } function Get-PRTGProbe { <# .Synopsis Get-PRTGProbe .DESCRIPTION Returns one or more probes from sensortree .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Get-PRTGProbe Query all probes from the default sensortree (global variable after connect to PRTG server) Get-PRTGProbe -SensorTree $SensorTree Query probes by name from a non default sensortree .EXAMPLE Get-PRTGProbe -Name "Probe01" Query probes by name Get-PRTGProbe -Name "Probe01", "Probe*" # Multiple names are possible "Probe01" | Get-PRTGProbe # Piping is also possible .EXAMPLE Get-PRTGProbe -ObjectId 1 Query probes by object ID Get-PRTGProbe -ObjID 1, 100 Get-PRTGProbe -ID 1, 100 -SensorTree $SensorTree # Multiple IDs are possible 1 | Get-PRTGProbe # Piping is also possible #> [CmdletBinding( DefaultParameterSetName = 'ReturnAll', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( # ID of the PRTG object [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'ID', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( {$_ -gt 0})] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # Name of the Probe [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'Name', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [String[]] $Name, # sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin { $queryParam = @{ "Type" = "probenode" "SensorTree" = $SensorTree "Verbose" = $false } } process { $result = @() switch ($PsCmdlet.ParameterSetName) { 'ID' { foreach ($item in $ObjectId) { $result += Get-PRTGObject -ObjectID $item @queryParam } } 'Name' { foreach ($item in $Name) { $result += Get-PRTGObject -Name $item @queryParam } } Default { $result = Get-PRTGObject @queryParam } } $result } end {} } function Get-PRTGSensor { <# .Synopsis Get-PRTGSensor .DESCRIPTION Returns one or more sensors from sensortree .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PoShPRTG .EXAMPLE Get-PRTGSensor Query all sensors from the default sensortree (global variable after connect to PRTG server) .EXAMPLE Get-PRTGSensor -SensorTree $SensorTree Query sensors by name from a non default sensortree .EXAMPLE Get-PRTGSensor -Name "Sensor01" Query sensors by name .EXAMPLE Get-PRTGSensor -Name "Sensor01", "Sensor*" Multiple names are possible .EXAMPLE "Sensor01" | Get-PRTGSensor Piping is also possible .EXAMPLE Get-PRTGSensor -ObjectId 1 Query sensors by object ID .EXAMPLE 1 | Get-PRTGSensor Piping is also possible #> [CmdletBinding( DefaultParameterSetName = 'ReturnAll', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( # ID of the PRTG object [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'ID', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript( { $_ -gt 0 })] [Alias('ObjID', 'ID')] [int[]] $ObjectId, # Name of the sensor [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'Name', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [String[]] $Name, # Sensortree from PRTG Server [ValidateNotNullOrEmpty()] [xml] $SensorTree = $script:PRTGSensorTree ) begin { $queryParam = @{ "Type" = "sensor" "SensorTree" = $SensorTree "Verbose" = $false } } process { $result = @() switch ($PsCmdlet.ParameterSetName) { 'ID' { foreach ($item in $ObjectId) { $result += Get-PRTGObject -ObjectID $item @queryParam } } 'Name' { foreach ($item in $Name) { $result += Get-PRTGObject -Name $item @queryParam } } Default { $result = Get-PRTGObject @queryParam } } $result } end {} } <# This is an example configuration file By default, it is enough to have a single one of them, however if you have enough configuration settings to justify having multiple copies of it, feel totally free to split them into multiple files. #> <# # Example Configuration Set-PSFConfig -Module 'PoShPRTG' -Name 'Example.Setting' -Value 10 -Initialize -Validation 'integer' -Handler { } -Description "Example configuration setting. Your module can then use the setting using 'Get-PSFConfigValue'" #> Set-PSFConfig -Module 'PoShPRTG' -Name 'Import.DoDotSource' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be dotsourced on import. By default, the files of this module are read as string value and invoked, which is faster but worse on debugging." Set-PSFConfig -Module 'PoShPRTG' -Name 'Import.IndividualFiles' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be imported individually. During the module build, all module code is compiled into few files, which are imported instead by default. Loading the compiled versions is faster, using the individual files is easier for debugging and testing out adjustments." <# Stored scriptblocks are available in [PsfValidateScript()] attributes. This makes it easier to centrally provide the same scriptblock multiple times, without having to maintain it in separate locations. It also prevents lengthy validation scriptblocks from making your parameter block hard to read. Set-PSFScriptblock -Name 'NPSLogFile.ScriptBlockName' -Scriptblock { } #> <# # Example: Register-PSFTeppScriptblock -Name "PoShPRTG.alcohol" -ScriptBlock { 'Beer','Mead','Whiskey','Wine','Vodka','Rum (3y)', 'Rum (5y)', 'Rum (7y)' } #> <# # Example: Register-PSFTeppArgumentCompleter -Command Get-Alcohol -Parameter Type -Name PoShPRTG.alcohol #> New-PSFLicense -Product 'PoShPRTG' -Manufacturer 'Andreas Bellstedt' -ProductVersion $script:ModuleVersion -ProductType Module -Name MIT -Version "1.0.0.0" -Date (Get-Date "2019-01-05") -Text @" Copyright (c) 2019 Andreas Bellstedt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. "@ #endregion Load compiled code |