lordmilko / PrtgAPI

C#/PowerShell interface for PRTG Network Monitor
MIT License
301 stars 37 forks source link

New-SearchFilter not URLEncoding "(" and ")" in expression #266

Closed JRAndreassen closed 2 years ago

JRAndreassen commented 2 years ago

Describe the bug

The "(" and ")" in the expression are not URL Encoded...

$Local:filter = New-SearchFilter name contains "[XXX] TX - Midland (XXX-Edge840) (YYY Ent:170)"
When I do Verbose I get these:
filter_name=@sub(%5BXXX%5D+TX+-+Midland+(XXX-Edge840)+(YYY+Ent%3A170))
filter_name=%5BXXX%5D+TX+-+Midland+(XXX-Edge840)+(YYY+Ent%3A170)

It should be:
%5BXXX%5D%20TX%20-%20Midland%20%28YYY%20Ent%3A170%29

Steps to reproduce

$Local:filter = New-SearchFilter name contains "[XXX] TX - Midland (XXX-Edge840) (YYY Ent:170)"
$Local:filter | get-group

What is the output of 'Get-PrtgClient -Diagnostic'?

Get-Device: Synchronously executing request https://*****.com/api/table.xml?content=devices&columns=objid,name,location,host,group,probe,fa
vorite,condition,upsens,downsens,downacksens,partialdownsens,warnsens,pausedsens,unusualsens,undefinedsens,totalsens,schedule,basetype,baselink,no
tifiesx,intervalx,access,dependency,position,status,comments,priority,message,parentid,tags,type,active&count=*&filter_name=@sub(%5BXXX%5D+TX+-+Mi 
dland+(XXX-Edge840)+(YYY+Ent%3A170))

Additional context

No response

lordmilko commented 2 years ago

Hi @JRAndreassen,

I can confirm that the search filter value [XXX] TX - Midland (XXX-Edge840) (YYY Ent:170) is passed to WebUtility.UrlEncode; as such this indicates to me that parentheses do not need to be URL encoded. I can see that when attempt to search for a group using the name you've specified it does appear to work as expected.

lordmilko commented 2 years ago

Based on RFC 1738.2.2 it seems parentheses may be used unencoded within a URL

Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
reserved characters used for their reserved purposes may be used
unencoded within a URL.
JRAndreassen commented 2 years ago

Hi @lordmilko , Thanks for checking...

Be that as it may... Searches fail.... Here is the work-arround:

function PRTGCGetSearchExpression {
    # $Filters = PRTGCGetSearchExpression -WhatToFind "AMC" -fieldName "Name" 
    param (
        [String]$WhatToFind,
        [bool]$Exact = $false, 
        [String]$fieldName = "Name",
        [Bool]$count = 1
    )
    $retval = New-SearchFilter $fieldName contains $WhatToFind
    if ($Exact) {
        $retval = New-SearchFilter $fieldName equals $WhatToFind
    }
    if ($WhatToFind.contains("(") ) {
        $batches = $WhatToFind.replace("(", "@|@").replace(")", "@|@").split("@|@", [System.StringSplitOptions]::RemoveEmptyEntries)
        $retval = @()
        foreach ($curr in $batches) {
            $curr = $curr.trim()
            if ($curr ) {
                $retval += New-SearchFilter $fieldName contains $curr
            }
            $count -= 1
            if ($count -lt 1)
            { break}
        }
    }
    $retval
} # $Filters = PRTGCGetSearchExpression -WhatToFind $WhatToFind

function PRTGCFindGroup {
    # $grp = PRTGCFindGroup -NameToFind $yy -ObjectParent $xx
    param (
        [String]$NameToFind,
        $ObjectParent,
        [bool]$Exact = $false, 
        [bool]$firstOnly = $false, 
        [bool]$recurse = $false
    )
    $retVal = $null
    if ($NameToFind) {
        $Local:filter = PRTGCGetSearchExpression -WhatToFind $NameToFind -Exact:$exact
        if ($ObjectParent )
        {   $retVal = $Local:filter | Get-Group -ParentId $ObjectParent.Id -Recurse:$recurse }
        else 
        {   $retVal = $Local:filter | Get-Group  }
    }
    if ($retval.length -gt 1) {
        if ($Exact ) {
            $retval = $retval | Where-Object {$_.name -eq $NameToFind }
        } else {
            $retval = $retval | Where-Object {$_.name -contains $NameToFind }
        }
    }
    if ($firstOnly -and ($retval.length -gt 1)) {
        $retval = $retval[0]
    }
    $retval
}

function PRTGCFindDevice {
    # $device = PRTGCFindDevice -NameToFind $yy -ObjectParent $xx
    param (
        [String]$NameToFind,
        $ObjectParent,
        [bool]$Exact = $false, 
        [bool]$firstOnly = $false, 
        [bool]$recurse = $false
    )
    $retVal = $null
    if ($NameToFind) {
        $Local:filter = PRTGCGetSearchExpression -WhatToFind $NameToFind -Exact:$exact
        if ($ObjectParent) {
            $retVal = $Local:filter | Get-Device -ParentId $ObjectParent.Id -Recurse:$recurse
        } else {
            $retVal = $Local:filter | Get-Device
        }
    }
    if ($retval.length -gt 1) {
        if ($Exact ) {
            $retval = $retval | Where-Object {$_.name -eq $NameToFind }
        } else {
            $retval = $retval | Where-Object {$_.name -contains $NameToFind }
        }
    }
    if ($firstOnly -and ($retval.length -gt 0)) {
        $retval = $retval[0]
    }
    $retval
}

function PRTGCFindSensor {
    # $sensor = PRTGCFindSensor -NameToFind $yy -ObjectParent $xx
    param (
        [String]$NameToFind,
        $Objectparent,
        $tag = $null,
        $SensorType = $null,
        [bool]$Exact = $false, 
        [bool]$firstOnly = $false, 
        [bool]$recurse = $false
    )
    $retVal = $null
    $Local:filter = $null
    if ($NameToFind) {
        $Local:filter = PRTGCGetSearchExpression -WhatToFind $NameToFind -Exact:$exact
    } elseif ($tag) {
        $Local:filter = New-SearchFilter tag contains $tag
    }
    if ($Objectparent) 
    {  
        if (!$SensorType) {
            $retVal = $Local:filter | Get-Sensor -ParentId $Objectparent.Id -Recurse:$recurse 
        } else {
            $retVal = $Local:filter | Get-Sensor -Type $SensorType -ParentId $Objectparent.Id -Recurse:$recurse 
        }
    }
    else 
    {  
        if (!$SensorType) {
            $retVal = $Local:filter | Get-Sensor 
        } else {
            $retVal = $Local:filter | Get-Sensor -Type $SensorType
        }
    }

    if ($retval.length -gt 1) {
        if ($Exact ) {
            $retval = $retval | Where-Object {$_.name -eq $NameToFind }
        } else {
            $retval = $retval | Where-Object {$_.name -contains $NameToFind }
        }
    }
    if ($firstOnly -and ($retval.length -gt 1)) {
        $retval = $retval[0]
    }
    $retval
}
lordmilko commented 2 years ago

Hi @JRAndreassen,

Searches should not fail when a name contains a parenthesis. I observed a number of bugs in PRTG a few months ago relating to PRTG not querying names properly. Are you able to provide the output of Get-PrtgClient -Diagnostic and advise a name that is not working properly when you search for it?