03-31-2023 12:29 PM
Hey all,
Been trying to follow this documentation https://developer.cisco.com/docs/sxml/#!risport70-api-reference/selectcmdevice in order to grab RIS info for our cisco phones. The documentation states that I need to segment the request out by using the multiline item feature (which I did) but I am still not getting all of our devices back from the API call.
First, I grabbed all devices using Cisco AXL API and segmented out based off our primary location (since it has the largest cluster of phones ~over 1000) into another variable (described as "MyLocation"). Next, I segmented the large array of 1475 hostnames into 3 smaller arrays via hash table. The SOAP request was giving me issues trying to parse it out so I decided to assign the hash table arrays into their own variables.
$Locationquery = @()
foreach ($Device in $devices)
{
$Locationquery += $Device | Where {$device.devicepool -eq "MyLocation"}
}
$NumberOfArrays = 3; $LocationArrays = @{}; $i = 0; $Locationquery.devicename | %{$LocationArrays[$i % $NumberOfArrays] += @($_); $i++};
$LocationArrays[0] = $LocationArrays[0] -join ","
$LocationArrays[1] = $LocationArrays[1] -join ","
$LocationArrays[2] = $LocationArrays[2] -join ","
$LocationArrays1 = $LocationArrays[0]
$LocationArrays2 = $LocationArrays[1]
$LocationArrays3 = $LocationArrays[2]
Next, is the SOAP request I am sending to Risport70 (I've tried both SelectDeviceCM and SelectDeviceCMext with no luck). The documentation tells me to use the multiline notation to process the request (which I am doing below)
$RisBody = "<soapenv:Envelope xmlns:soapenv=`"http://schemas.xmlsoap.org/soap/envelope/`" xmlns:soap=`"http://schemas.cisco.com/ast/soap`">
<soapenv:Header/>
<soapenv:Body>
<soap:selectCmDevice>
<soap:StateInfo></soap:StateInfo>
<soap:CmSelectionCriteria>
<soap:MaxReturnedDevices>1000</soap:MaxReturnedDevices>
<soap:DeviceClass>Phone</soap:DeviceClass>
<soap:Model>255</soap:Model>
<soap:Status>Any</soap:Status>
<soap:NodeName></soap:NodeName>
<soap:SelectBy>Name</soap:SelectBy>
<soap:SelectItems>
<soap:item>
<soap:Item>($LocationArray1)</soap:Item>
</soap:item>
<soap:item>
<soap:Item>($LocationArray2)</soap:Item>
</soap:item>
<soap:item>
<soap:Item>($LocationArray3)</soap:Item>
</soap:item>
</soap:SelectItems>
<soap:Protocol>Any</soap:Protocol>
<soap:DownloadStatus>Any</soap:DownloadStatus>
</soap:CmSelectionCriteria>
</soap:selectCmDevice>
</soapenv:Body>
</soapenv:Envelope>"
My results vary by the SOAP request I use according to XML viewer
SelectDeviceCM nets me about 1100 devices
SelectDeviceCMExt nets me just over 1000
I realize that SelectDeviceCMExt gets rid of duplicates so thats why the number is lower but for the life of me can't understand why it wont fetch all 1475. I even ran my device table through excel to see if there were dupes of MAC addresses just in case. Anyone have an idea?
Thank you!
03-31-2023 12:38 PM
Hi,
Are you aware that selectCmDevice will only return devices that have been registered at least once? Perhaps some of your phones have not been registered yet, and are therefore not included in the response.
03-31-2023 12:46 PM
I'll look deeper into the Device list for registered and none. At this point in time, i dont think its possible that i have over 300 phones that havent registered at least once.
04-04-2023 04:57 AM
hey @npetrele, I did a manual pull of all my location phones, 7900 series and 8800 series with a total count of 1681 devices.
I reran the script this morning, results came back with only 1008 devices. Of the phones that were "unregistered/never registered" in this cluster, only came back with 9. I should be seeing a total of 1672 devices in the XML doc if my segmentation was working correctly. Is there a way to grab those last 600 devices?
Previously in our old RISport script (deprecated after upgrading CUCM), my coworker wrote this since I believe it could only grab 250 devices at a time. He looped the count so that it would match the total devices. Will the new Risport70 API take note of whats already grabbed from the initial query?
foreach ($device in $DeviceNames)
{
$loopCount += 1
$risQuery += $device
if (($risQuery.count -eq $queryAmount) -or ($loopCount -eq $devicenames.count))
{
$risQuery = $risQuery -join "," # join hostname together with comma and insert in soap request
$SOAPRequest = [Xml]"<soapenv:Envelope xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`" xmlns:xsd=`"http://www.w3.org/2001/XMLSchema`" xmlns:soapenv=`"http://schemas.xmlsoap.org/soap/envelope/`" xmlns:soap=`"http://schemas.cisco.com/ast/soap/`" xmlns:soapenc=`"http://schemas.xmlsoap.org/soap/encoding/`">
<soapenv:Body>
<soap:SelectCmDevice soapenv:encodingStyle=`"http://schemas.xmlsoap.org/soap/encoding/`">
<CmSelectionCriteria xsi:type=`"soap:CmSelectionCriteria`">
<MaxReturnedDevices xsi:type=`"xsd:unsignedInt`">999</MaxReturnedDevices>
<Class xsi:type=`"xsd:string`">Any</Class>
<Model xsi:type=`"xsd:unsignedInt`">255</Model>
<Status xsi:type=`"xsd:string`">Any</Status>
<NodeName xsi:type=`"xsd:string`"></NodeName>
<SelectBy xsi:type=`"xsd:string`">Name</SelectBy>
<SelectItems>
<Item>$($risQuery)</Item>
</SelectItems>
</CmSelectionCriteria>
</soap:SelectCmDevice>
</soapenv:Body>
</soapenv:Envelope>"
try { $response = (iwr $url -Body $SOAPRequest –contentType "text/xml;charset=UTF-8" –method POST -Credential $creds -Headers $headers) }
catch { throw "SOAP request failed - $($_[0].exception.message)" }
try
{
$xmlObj = [xml]$response.content
$XmlItems = ($xmlObj.SelectNodes("//item")) | where {(($_.type -match "CmNode") -or ($_.class."#text" -match "Phone|Gateway"))}
}
catch { throw "Problem parsing XML results - $($_[0].exception.message)" }
#parse results into hash table
foreach ($xmlItem in $XmlItems)
{
# if it's a CM server, assign the IP to a variable and move on
if ($xmlItem.type -match "CmNode")
{
$node = $xmlItem.Name."#text"
Continue
}
# otherwise, it should be a phone so build an object
$newObj = [pscustomobject]@{'Devicename'=$xmlItem.name."#text";'Ip'=$xmlItem.IpAddress."#text";
'Status'=$xmlItem.Status."#text";'Description'=$xmlItem.Description."#text";'Timestamp'=$xmlItem.TimeStamp."#text";'Server'=$node}
# if device name already in list under another cluster, compare timestamps and keep the more recent
if ($newObj.devicename -notin $parsedResponse.devicename)
{
$parsedResponse += $newObj
}
else
{
$existingObj = $parsedResponse | where {$_.Devicename -eq $newObj.Devicename} #grab existing obj with same devicename
#if new obj timestamp is more recent then replace, OR if timestamps are equal then keep whichever says registered.
if (($newObj.TimeStamp -gt $existingObj.TimeStamp) -or (($newObj.TimeStamp -eq $existingObj.TimeStamp) -and ($newObj.Status -eq "Registered")))
{
$existingObj.Ip = $newObj.Ip
$existingObj.Status = $newObj.Status
$existingObj.Description = $newObj.Description
$existingObj.TimeStamp = $newObj.TimeStamp
$existingObj.Server = $newObj.Server
}
}
}
$risQuery = @() # reset for next 250 query
}
}
04-04-2023 07:33 AM
Hi,
I'm not following your code's logic. You have
<MaxReturnedDevices xsi:type=`"xsd:unsignedInt`">999</MaxReturnedDevices>
Which tells it to return 999, (the maximum is 1000), but you reset for 250? We don't have 1,000 devices in our lab for me to test with, but I'm pretty sure the max is 1000 like the docs say, not 250.
How did you determine the number of phones never registered?
04-04-2023 07:44 AM
So the script i sent a screenshot of was old and it would target the old Risport schema. I think there was a cap on previous instances of returned devices or the former co-worker set that hard limit.
I confirmed number of phones never registered by manually going to Call Manager, searching all devices, and pulling them into an excel sheet for easy filtering.
04-04-2023 09:04 AM - edited 04-04-2023 09:05 AM
It looks like the code is creating a long string of individual device names concatenated with commas, e.g.:
<soap:SelectItems>
<soap:item>
<soap:Item>CSFDSTAUDT,SEP001EF727852D</soap:Item>
</soap:item>
</soap:SelectItems>
I've not actually seen that before, and...it apparently works; surprising! I suspect, however, that there may be some issue with AXL parsing such gigantic strings, and may be losing some devices that way...
However, the intended format for querying multiple device is like:
<soap:SelectItems>
<soap:item>
<soap:Item>CSFDSTAUDT</soap:Item>
</soap:item>
<soap:item>
<soap:Item>SEP001EF727852D</soap:Item>
</soap:item>
</soap:SelectItems>
with up to 1000 (I believe this is up to 2000 now in all the extant CUCM versions - will update the docs) individual device entries.
To query 'blocks' of devices (e.g. 250 or 500 at a time), you would submit multiple separate <selectCmDevice> SOAP requests, each containing <SelectItems> with 250/500 devices included.
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide