Netscaler Rewrite complete HTTP Request Body before sending to the backend server

You may run into cases where the sending application has one set of message standards and the receiving service has its own standards. One such case that I recently ran into with an app trying to initiate a call request via vendor-neutral open standards to Cisco Unified communication system. Obviously, Cisco expects the API request to be in its own format and some process needs to do this translation/transformation to complete the request successfully.

Cisco has good documentation on these Call APIs, also published a sample java application which can be found at https://developer.cisco.com/site/webdialer/

Netscaler Rewrite Action can be levered to transform the HTTP REQ Body to Cisco desired format. Below is a rewrite action that I used to bridge the gap, Basically, replaced the message body to Cisco specifications from the extracted information of the original message.

Expression

Note: Had to break the expression strings in chucks of ~200 char’s to please Netscaler character limitation. Also, while I could have used XPATH to extract the desired information, I went with regex as it turned out to be faster during testing.

"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:urn=\"urn:WD70\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instanc"+"e\"><soapenv:Header /><soapenv:Body><urn:makeCallSoap soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><in0 xsi:type=\"urn:Credential\"><userID xsi:type=\"xsd:string\">username"+"</userID><password xsi:type=\"xsd:string\">******</password></in0><in1 xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xsi:type=\"soapenc:string\">" + HTTP.REQ.BODY(HTTP.REQ.CONTENT_LENGTH).AFTER_REGEX(re/<PhoneNumber>/).Before_REGEX(re/<.PhoneNumber>/) + "</in1><in2 xsi:type=\"urn:UserProfile"+"\"><user xsi:type=\"xsd:string\">?</user><deviceName xsi:type=\"xsd:string\">CSF" + HTTP.REQ.BODY(HTTP.REQ.CONTENT_LENGTH).AFTER_REGEX(re/<PhoneAgentID>/).Before_REGEX(re/<.PhoneAgentID>/).TO_UPPER + "</deviceName><lineNumber xsi:type=\"xsd:string\">?</lineNumber></in2></urn:makeCallSoap></soapenv:Body></soapenv:"+"Envelope>"

References >

https://www.citrix.com/blogs/2014/03/03/creating-policies-greater-than-255-characters/

https://developer.cisco.com/site/webdialer/

Extract ICA client public IP from ADM/MAS HDX INSIGHT data

If you tasked to find the public IP for all your ICA clients you will be surprised to know the Citrix monitoring/ODATA in virtual apps and desktops do not have this data.

If you have Citrix ADM/MAS in place and your ADC/Netscaler is on Premium/Platinum license, you are in luck and this could be your source for this kind of data but it doesn’t have a data export function from the web UI. This is where NITRO comes to the rescue, In fact, the Web interface for ADM/MAS gets the data through the NITRO API resources behind the scenes.

Here are some URLs that could help get the data you may seek, initially to explore the data you may start off by just navigating to these URL paths directly using any web browser. you will be prompted for credentials which would your ADM/MAS login. If it piques your interest, you may move to POSTMAN or PowerShell to automate & filter JSON responses.

Active ICA Sessions

https://ADM_IP-ADDRESS/nitro/v1/appflow/ica_session?asc=no&pagesize=250&duration=last_1_day

Historical ICA Sessions

https://ADM_IP-ADDRESS/nitro/v1/appflow/ica_session_inactive?asc=no&pagesize=250&duration=last_1_year

Both URLS above provide a JSON response with intresting fields eg: client_version, client_type, client_ip_address, terminated_reason etc..

For the full list of fields refer to https://github.com/citrix/mas-nitro-api-reference/blob/master/docs/configuration/analytics/hdx-insight/ica_session.md

Citrix Monitoring ODATA API

Function Get-LocalTime($UTCTime)
{
$strCurrentTimeZone = "Eastern Standard Time"
$TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById($strCurrentTimeZone)
$LocalTime = [System.TimeZoneInfo]::ConvertTimeFromUtc($UTCTime, $TZ)
Return $LocalTime
}

$datescope = (get-date).AddHours(-3).ToUniversalTime()
$datescope = get-date($datescope) -Format s
$filename = "SessionActivitySummariesByMinute-" + (get-date ($datescope) -f "MM-yyyy") + ".csv"
$uri = "http://localhost/Citrix/Monitor/OData/v3/Data/SessionActivitySummaries()?`$filter=Granularity eq 1 and SummaryDate gt DateTime`'$datescope`' &amp;`$select=DesktopGroup/Name,SummaryDate,ConcurrentSessionCount,ConnectedSessionCount,DisconnectedSessionCount&amp;`$orderby=SummaryDate asc&amp;`$expand=DesktopGroup&amp;`$format=json"
$records = Invoke-RestMethod -Uri $uri -UseDefaultCredentials
$records.value | Select-Object @{Name='SummaryDateEST';Expression={Get-LocalTime($_.SummaryDate)}},ConcurrentSessionCount,ConnectedSessionCount,DisconnectedSessionCount,@{Name='DesktopGroupName';Expression={$_.DesktopGroup.Name}} | Export-csv .\$filename -NoTypeInformation -Append



Citrix provides access to Monitoring Data via ODATA API, I find it useful to extract session info to a very granular level [eg: by mintue]. This is the same data Citrix Director uses to present the fancy usage graphs but as you expand to longer time series it averages it and you might not get the accurate insights for capacity planning. The PS code shown above extracts and exports the SessionActivitySummary by minute to a csv file. the reason for the export is Citrix purges the ByMinute data, by default it only retains it for last 3 days. you could override this default retention value using Set-MonitoringConfiguration . I find it easy to export and generate graphs using pivot tables in excel.

The PS script above could you used to set up as scheduled tasks on a controller and set to run every 3 hours. This provides a way to archive the data as well as leaving the default retention values in Citrix.

Download code from https://github.com/Siva-Github/PS-Scripts-Repo/blob/main/SessionActivitySummariesByMinute-ODATA.ps1

DUO ADMIN API Functions through PowerShell

https://github.com/Siva-Github/Duo-PSModule

Forked from Duo-PSModule by mbegan, added new Administrator Activation Link functions. this automates the provisioning process to the duo admin console and lets you create the account with just corp email whereas GUI forces you to enter temp password and require to key in the user’s phone #.

Extract MFA/StrongAuth information from all Azure/O365 users

MSOnline PowerShell module is required to run this, the new AzureAD commandlets do not appear to have the strong authentication properties yet. Run the following PowerShell lines to load and connect to your Azure/o365 tenant.

Install-Module -Name MSOnline 
Connect-MsolService

Powershell snippet below gets all user from the tenant and expands StrongAuthenticationUserDetails property to retrieve the enrolled MFA info and further extends to extract default MFA method using PowerShell expression and saves it to c:\tmp\Azure-2FAEnrollmentReport.csv, using PS expression we were able to expand the second property in a single line.

Get-MsolUser -All | select userprincipalname, DisplayName,title, Department -ExpandProperty StrongAuthenticationUserDetails | select UserPrincipalName,DisplayName,Title,Department,AlternativePhoneNumber,PhoneNumber, @{ Name = 'default2FAMethodType'; Expression = {  (Get-MsolUser -UserPrincipalName $_.UserPrincipalName  | select -ExpandProperty StrongAuthenticationMethods | where {$_.IsDefault}).MethodType }} | Export-csv c:\tmp\Azure-2FAEnrollmentReport.csv

Update windows root ca list – offline

Download the latest version of root ca list [SST] from windows update on a device that has network connection
certutil.exe -generateSSTFromWU roots.sst
copy the sst file to the offline machine and use powershell to import the root ca list.

$sst = ( Get-ChildItem -Path C:\certs\roots.sst )
$sst | Import-Certificate -CertStoreLocation Cert:\LocalMachine\Root

A quick way to generate self-signed certs through PowerShell

code snippet to generate a 10-year SSL self-signed cert, notice the NotAfter argument.

New-SelfSignedCertificate -DnsName "i7host" -CertStoreLocation "cert:\LocalMachine\My" -KeyAlgorithm RSA -KeyLength 2048 -NotAfter (Get-Date).AddYears(10)

Once successfully run, cert can be exported through local machine certificate MMC. New-SelfSignedCertificate command-let is available in windows 8.1 and above.

Force specific IP traffic through a network interface [Windows 8+]

In a case where you have two network interfaces, eg: 4G data card and local ethernet card connect to your device and you would like traffic to a specific destination to go via a preferred network interface, PS code below could guide you through it.

E.g ps code below shows the route to 200.200.200.200 to go through interface 4, this is done by setting a lower route metric than the other interface card.

# you can determine your adapters with Get-NetAdapter
Get-NetAdapter -IncludeHidden
# then you can see what routes are associated with what adapter interface (lets assume your wifi interface is 4 and your loopback is 1)
Get-NetRoute -AddressFamily IPv4
# you will get your specific interface index, destination prefix, nexthop and the routemetric
# you can then set a specific route policy using:
New-NetRoute -DestinationPrefix "200.200.200.200/32" -InterfaceIndex 1 -RouteMetric 256
New-NetRoute -DestinationPrefix "200.200.200.200/32" -InterfaceIndex 4 -NextHop10.1.1.1 -RouteMetric 0
# you can modify the configuration with:
Set-NetRoute -DestinationPrefix "200.200.200.200/32" -InterfaceIndex 4 -NextHop192.168.10.1 -RouteMetric 0
# finally, you can remove the specific route or all the routes with:
Remove-NetRoute -DestinationPrefix "200.200.200.200/32" -InterfaceIndex 1 -Confirm:$false
Remove-NetRoute -DestinationPrefix "200.200.200.200/32" -Confirm:$false

Credit to Brandon Records