This is the second in a series of articles giving extended example of how to use the RestAPI. This article will demonstrate how to generate a report equivalent to the Version 3 "OutputApplications" view using PowerShell. For a shorter example that returns a simpler dataset, you can see the article Use RestAPI and PHP to generate a list of Applications.
Fields in the original report
Field Name | V3 Description | V4 Comment |
---|---|---|
Hostname | The hostname of the device the application is running on | Get this from the Applications endpoint. |
FQDN | Fully Qualified Domain Name of the device | Get this from the Applications endpoint. |
SoftwareName | SoftwareName Enterprise application name | Get this from the Applications endpoint. |
SoftwareVersion | Version | Get this from the Applications endpoint. |
SoftwareVendor | Software vendor name | Get this from the Applications endpoint. |
SoftwareEdition | Software Edition (Enterprise, Web, etc) | Get this from the Applications endpoint where applicable. |
InstanceIdentifier | Unique application name | Use the name field in the Applications endpoint. For database applications, this is in the "instance" name. For VMWare clusters it is the node name, etc. |
ClusterInformation | The cluster that the physical machine is part of. | See clusters and/or parent_cluster in the Applications endpoint. IN V3 this contained the cluster name and list of nodes separated by ";" for some cluster types, but not all |
UserCount | Number of users (where applicable) | Get this from the Applications/Application_ID endpoint |
LastScanDate | Timestamp of last scan | Get this from the Applications endpoint. |
Location | Location of the application (user defined, inherited from the device location) | Get this from the Applications endpoint device section for non-clustered applications. |
Language | SQL Server instance language (SQL Server only) | Not exposed via V4 RestAPI |
ApplicationID | Unique Identifier for the application | Get this from the Applications endpoint. |
DeviceID | Unique Identifier for the device. Can be used to map to OutputDevices | Get this from the Applications endpoint device section for non-clustered applications. |
DNSHostname | The hostname for the device as reported by DNS | Get this from the Applications endpoint device section for non-clustered applications. |
DNSFQDN | The FQDN for the device as reported from DNS | Get this from the Applications endpoint device section for non-clustered applications. |
Evidence | This column not available in V4 | Not exposed via V4 RestAPI |
Connect to the RestAPI
The RestAPI uses HTTP basic authentication rather than domain credentials. To write a script that extracts data from the RestAPI you will need to know the login name and password for an iQSonar user who has the "access Rest API" permission enabled. By default the admin user always has this permission. These variables will need to be configured for your site:
$user = "admin" $pass = "password" $sonar = "iQSonar Host" $secpass = ConvertTo-SecureString $pass -AsPlainText -Force $credential = New-Object System.Management.Automation.PSCredential($user,$secpass)
The first step is to determine exactly how many applications we're going to be collecting data for. This information is returned in the header of the RestAPI return value. By default a call to the devices endpoint will return a batch of 200 devices, and the user is expected to page through the list of available devices by making successive calls to this endpoint using an offset parameter to specify how many devices have already been seen. The fetch_size parameter is used to determine how many devices are returned per batch. The fastest way to determine the total number of available applications is to explicitly request the first device only. Since we want data from the headers of the result, we use the Invoke-WebRequest PowerShell cmdlet to get this information.
$uri = -join ("http://", $sonar, "/api/v1/applications/?offset=1&fetch_size=1") $r = Invoke-WebRequest $uri -Credential $credential # $r.headers has HTML headers, $r.content has text content $appCount = $r.headers.'X-fetch-count'
Build the CSV file header row
PowerShell has a number of built in libraries for handling output to various file formats. For this example we will be saving the results in a CSV file that can be viewed directly in EXCEL or imported into other databases.
Error rendering macro 'code': Invalid value specified for parameter 'firstline'# Build the CSV File header row $csv = @() $row = New-Object System.Object $row | Add-Member -MemberType NoteProperty -Name "Hostname" -Value $null $row | Add-Member -MemberType NoteProperty -Name "FQDN" -Value $null $row | Add-Member -MemberType NoteProperty -Name "SoftwareName" -Value $null $row | Add-Member -MemberType NoteProperty -Name "SoftwareVersion" -Value $null $row | Add-Member -MemberType NoteProperty -Name "SoftwareVendor" -Value $null $row | Add-Member -MemberType NoteProperty -Name "SoftwareEdition" -Value $null $row | Add-Member -MemberType NoteProperty -Name "InstanceIdentifier" -Value $null $row | Add-Member -MemberType NoteProperty -Name "ClusterInformation" -Value $null $row | Add-Member -MemberType NoteProperty -Name "UserCount" -Value $null $row | Add-Member -MemberType NoteProperty -Name "LastScanDate" -Value $null $row | Add-Member -MemberType NoteProperty -Name "Location" -Value $null $row | Add-Member -MemberType NoteProperty -Name "Language" -Value $null $row | Add-Member -MemberType NoteProperty -Name "ApplicationID" -Value $null $row | Add-Member -MemberType NoteProperty -Name "DeviceID" -Value $null $row | Add-Member -MemberType NoteProperty -Name "DNSHostname" -Value $null $row | Add-Member -MemberType NoteProperty -Name "DNSFQDN" -Value $null $row | Add-Member -MemberType NoteProperty -Name "Evidence" -Value $null
The inner and outer loops
We need to iterate over the list of applications, fetching Fetch_Size applications per batch, then processing each application one at a time, until we have dealt with all of them. Then we save the resulting CSV file. As a large dataset may take some time to process, we display a status indicator to give feedback to the user. For a more detailed breakdown on how this is developed, see the OutputDevices example article.
$offset = 1 # offset $seen = 1; # first offset is 1, not 0 while ( $seen -lt $appCount) { $url = -join ("http://", $sonar, "/api/v1/applications/?offset=", $offset, "&fetch_size=", $fs) $applications = Invoke-RestMethod $url -Credential $credential $i = 1 while ($i -lt $applications.count) { # Process $applications[$i] $csv += $row $i = $i + 1; # keep track for inner loop $seen = $seen + 1; # keep track for outer loop if ( $seen % 10 -eq 0) { # progress indicator - display a "." every 10 devices write-host "." -nonewline } } # Finished this batch $offset = $seen } write-host " Done. Saving output to OutputApplications.csv now." $csv | Export-csv OutputApplications.csv -NoTypeInformation # We will further refine this line later
Process each application
# # Incomplete Code # # Process the $applications[$i] $thisApplication = $applications[$i] $currDevice = Invoke-RestMethod $thisApplication.self -Credential $credential $row = New-Object System.Object # Hostname, FQDN and DeviceID are defined by the devices subsection if present. if ( $thisApplication.devices.count -eq 0) { # If we have no devices, we do not have this info $row | Add-Member -MemberType NoteProperty -Name "Hostname" -Value $null $row | Add-Member -MemberType NoteProperty -Name "FQDN" -Value $null $row | Add-Member -MemberType NoteProperty -Name "DeviceID" -Value $null $row | Add-Member -MemberType NoteProperty -Name "DNSHostname" -Value $null $row | Add-Member -MemberType NoteProperty -Name "DNSFQDN" -Value $null } else { # one or more devices. So we will list the details for devices[0] - other devices will get listed in the cluster info section $row | Add-Member -MemberType NoteProperty -Name "Hostname" -Value $thisApplication.devices[0].host_name $row | Add-Member -MemberType NoteProperty -Name "DeviceID" -Value $thisApplication.devices[0].device_id $row | Add-Member -MemberType NoteProperty -Name "DNSHostname" -Value $thisApplication.devices[0].host_name $k=0 while ($k -lt $thisApplication.devices[0].qualified_name.count) { if ($thisApplication.devices[0].qualified_name[$k].name_type -eq "DNSFQDN") { $row | Add-Member -MemberType NoteProperty -Name "FQDN" -Value $null $row | Add-Member -MemberType NoteProperty -Name "DNSFQDN" -Value $null } $k = $k + 1 } } if () # Device name was complicated. Software details are more simple $row | Add-Member -MemberType NoteProperty -Name "SoftwareName" -Value $thisApplication.product.name $row | Add-Member -MemberType NoteProperty -Name "SoftwareVersion" -Value $thisApplication.version $row | Add-Member -MemberType NoteProperty -Name "SoftwareVendor" -Value $thisApplication.product.vendor $row | Add-Member -MemberType NoteProperty -Name "SoftwareEdition" -Value $thisApplication.edition $row | Add-Member -MemberType NoteProperty -Name "InstanceIdentifier" -Value $thisApplication.name # UserCount is optional if ( (!test-var variable:\$currDevice.users) ) { $row | Add-Member -MemberType NoteProperty -Name "UserCount" -Value $currDevice.users.count } $row | Add-Member -MemberType NoteProperty -Name "LastScanDate" -Value $thisApplication.last_scan $row | Add-Member -MemberType NoteProperty -Name "ApplicationID" -Value $thisApplication.application_id # Deal with clusters -- this gets hairy, finish it tomorrow