Citrix DaaS REST APIs

How to nest multiple properties within search filters in Citrix DaaS

Many advanced search APIs in Citrix DaaS (formerly Citrix Virtual Apps and Desktops service) — for example, machine search, session search, configuration log search, and delivery group search — accept a flat list of SearchFilters that are combined with an implicit AND. When you need to express more complex conditions that mix AND and OR (for example, “machines that belong to delivery group DG1 OR DG2, AND are in Unregistered state”), use the nested SearchFilterGroups model instead.

This how-to uses the machine search API as the primary example, but the same nesting model applies to every search endpoint that accepts the MachineAndSessionSearchRequestModel (and its sibling search request models).

You can make API requests using the PowerShell code, C# code, Python, or any tool that supports invoking the REST API.

Prerequisites to nest multiple properties within search filters

Understanding the nested search filter model

A search request body has two top-level fields that drive the nesting:

  • SearchFilterGroups — an array of nested groups.
  • SearchFilterGroupsType — the logical operator (And or Or) used to combine all top-level groups in the array.

Each item in SearchFilterGroups is itself a group. A group is either a leaf group (a flat list of filters joined by one operator) or a parent group (a list of nested child groups joined by one operator) — never both at the same time:

  • Leaf group fields:
    • SearchFilters — a flat list of leaf filters at this level. Each leaf filter has Property, Value, and Operator.
    • SearchFilterGroupType — the logical operator (And or Or) used to combine the items in SearchFilters. Note the singular form — this describes how the leaves of this group are combined.
  • Parent group fields:
    • SearchFilterGroups — an array of further nested child groups.
    • SearchFilterGroupsType — the logical operator (And or Or) used to combine the child groups in the nested SearchFilterGroups array. Note the plural form — this describes how the nested groups are combined.

If a single group provides both SearchFilters and SearchFilterGroups, the nested SearchFilterGroups take precedence and the leaf SearchFilters (and the singular SearchFilterGroupType) are ignored, so use one or the other within any given group.

When you only need a flat AND of filters, you can keep using the simple top-level SearchFilters array described in the existing search how-to articles. Use SearchFilterGroups only when you need to mix AND and OR.

Nest multiple properties within search filters using any REST API tool

The following example searches for machines that belong to delivery group DG1 OR DG2, AND are in Unregistered state. It demonstrates one level of nesting — an outer And that combines an inner Or group with a single equality filter.

For details on the request model, see the API specification.

Request

POST https://api.cloud.com/cvad/manage/Machines/$search HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Authorization: CWSAuth bearer=<token-from-prerequisites>
Citrix-CustomerId: loy6oujtu6a4
Citrix-InstanceId: 22ded57c-0306-47e4-b6e8-fed6252759e1

{
    "SearchFilterGroups": [
        {
            "SearchFilterGroupsType": "Or",
            "SearchFilterGroups": [
                {
                    "SearchFilterGroupType": "And",
                    "SearchFilters": [
                        {
                            "Property": "DeliveryGroup",
                            "Value": "DG1",
                            "Operator": "ContainsLike"
                        }
                    ]
                },
                {
                    "SearchFilterGroupType": "And",
                    "SearchFilters": [
                        {
                            "Property": "DeliveryGroup",
                            "Value": "DG2",
                            "Operator": "ContainsLike"
                        }
                    ]
                }
            ]
        },
        {
            "SearchFilterGroupType": "And",
            "SearchFilters": [
                {
                    "Property": "RegistrationState",
                    "Value": "Unregistered",
                    "Operator": "Equals"
                }
            ]
        }
    ],
    "SearchFilterGroupsType": "And"
}
<!--NeedCopy-->

How the body maps back to the original question:

  1. The two top-level entries in SearchFilterGroups are joined by the top-level SearchFilterGroupsType: "And".
  2. The first top-level entry is a parent group whose SearchFilterGroupsType is Or. Its SearchFilterGroups array contains the two child leaf groups for DG1 and DG2, joined by Or.
  3. The second top-level entry is a leaf group whose SearchFilters contains the single RegistrationState = Unregistered filter.

The result is the boolean expression: (DeliveryGroup ~ "DG1" OR DeliveryGroup ~ "DG2") AND (RegistrationState = Unregistered).

Response

The response shape is identical to a regular machine search response. See How to perform an advanced search for machines for an example.

Nest multiple properties within search filters using PowerShell

Learn from the following example to nest multiple properties within search filters using PowerShell code.

function SearchMachinesWithNestedFilters {
    param (
        [Parameter(Mandatory=$true)]
        [string] $customerid,
        [Parameter(Mandatory=$true)]
        [string] $siteid,
        [Parameter(Mandatory=$true)]
        [string] $bearerToken,
        [Parameter(Mandatory=$true)]
        [string] $body
    )
    $requestUri = "https://api.cloud.com/cvad/manage/Machines/`$search"
    $headers = @{
        "Accept" = "application/json";
        "Authorization" = "CWSAuth Bearer=$bearerToken";
        "Citrix-CustomerId" = $customerid;
        "Citrix-InstanceId" = $siteid;
        "Content-Type" = "application/json";
    }

    $response = Invoke-RestMethod -Uri $requestUri -Method POST -Headers $headers -Body $body
    return $response
}

$customerId = "customer1"
$siteId = "61603f15-cdf9-4c7f-99ff-91636601a795"
$bearerToken = "ey1.."
$body = @"
{
    "SearchFilterGroups": [
        {
            "SearchFilterGroupsType": "Or",
            "SearchFilterGroups": [
                {
                    "SearchFilterGroupType": "And",
                    "SearchFilters": [
                        { "Property": "DeliveryGroup", "Value": "DG1", "Operator": "ContainsLike" }
                    ]
                },
                {
                    "SearchFilterGroupType": "And",
                    "SearchFilters": [
                        { "Property": "DeliveryGroup", "Value": "DG2", "Operator": "ContainsLike" }
                    ]
                }
            ]
        },
        {
            "SearchFilterGroupType": "And",
            "SearchFilters": [
                { "Property": "RegistrationState", "Value": "Unregistered", "Operator": "Equals" }
            ]
        }
    ],
    "SearchFilterGroupsType": "And"
}
"@
$response = SearchMachinesWithNestedFilters $customerId $siteId $bearerToken $body
<!--NeedCopy-->

Nest multiple properties within search filters using C# code

Learn from the following example to nest multiple properties within search filters using C# code.

public static async Task<string> SearchMachinesWithNestedFilters(
    string customerid,
    string siteid,
    string bearerToken,
    MachineAndSessionSearchRequestModel model)
{
    var requestUri = "https://api.cloud.com/cvad/manage/Machines/$search";
    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
        client.DefaultRequestHeaders.Add("Citrix-CustomerId", customerid);
        client.DefaultRequestHeaders.Add("Citrix-InstanceId", siteid);
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("CWSAuth Bearer=" + bearerToken);

        var jsonBody = JsonConvert.SerializeObject(model, new JsonSerializerSettings
        {
            Converters = new JsonConverter[] { new StringEnumConverter() }
        });

        var response = await client.PostAsync(requestUri, new StringContent(jsonBody, Encoding.UTF8, "application/json"));

        if (response != null)
        {
            var content = await response.Content.ReadAsStringAsync();
            return content;
        }

        return null;
    }
}
<!--NeedCopy-->

Nest multiple properties within search filters using Python

Learn from the following example to nest multiple properties within search filters using Python.

import requests
import json

def search_machines_with_nested_filters(bearerToken, customerid, siteid):
    request_uri = "https://api.cloud.com/cvad/manage/Machines/$search"
    headers = {
                'Authorization': 'CWSAuth Bearer=%s' % bearerToken,
                'Citrix-CustomerId': customerid,
                'Citrix-InstanceId': siteid,
                'Content-Type': 'application/json',
                'Accept': 'application/json'
              }
    payload = json.dumps({
        "SearchFilterGroups": [
            {
                "SearchFilterGroupsType": "Or",
                "SearchFilterGroups": [
                    {
                        "SearchFilterGroupType": "And",
                        "SearchFilters": [
                            { "Property": "DeliveryGroup", "Value": "DG1", "Operator": "ContainsLike" }
                        ]
                    },
                    {
                        "SearchFilterGroupType": "And",
                        "SearchFilters": [
                            { "Property": "DeliveryGroup", "Value": "DG2", "Operator": "ContainsLike" }
                        ]
                    }
                ]
            },
            {
                "SearchFilterGroupType": "And",
                "SearchFilters": [
                    { "Property": "RegistrationState", "Value": "Unregistered", "Operator": "Equals" }
                ]
            }
        ],
        "SearchFilterGroupsType": "And"
    })

    response = requests.post(request_uri, headers = headers, verify = False, data = payload)

    return response.json()
<!--NeedCopy-->

Tips and limitations

  • Pay close attention to the singular versus plural property names. SearchFilterGroupType (singular) is the operator that joins the leaf SearchFilters of a group, and only takes effect on a leaf group. SearchFilterGroupsType (plural) is the operator that joins the items inside the nested SearchFilterGroups array, and only takes effect on a parent group (one that contains nested SearchFilterGroups). Mixing them up is the most common cause of unexpected results — pair SearchFilters with SearchFilterGroupType, and pair SearchFilterGroups with SearchFilterGroupsType.
  • The same nested model is accepted by other advanced search endpoints, including Sessions/$search. Refer to each endpoint’s API specification for the list of properties that the endpoint supports.
  • When you only need a flat AND of filters, prefer the simpler top-level SearchFilters array shown in How to perform an advanced search for machines and How to perform an advanced search for sessions.
Resources
Citrix DaaS REST APIs OpenAPI Specification
Copy Download
How to nest multiple properties within search filters in Citrix DaaS