cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
14044
Views
0
Helpful
6
Replies

Powershell Bulk Risport90 pull issue

sdrulik
Level 1
Level 1

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!

6 Replies 6

npetrele
Cisco Employee
Cisco Employee

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. 

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. 

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
        }
    }

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?

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. 

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.