In a recent post, I mentioned that sometimes filtering the Graph PowerShell commands doesn’t work.

https://helloitsliam.com/2021/10/18/sending-emails-using-microsoft-graph-powershell

It is not every command, but some take the filter but never return anything. The Microsoft Graph itself supports various types of filter operators, so the assumption is that Graph PowerShell supports them too.

  • Equality Operators: equals (eq), not equals (ne), negation (not), and in (in)
  • Relational Operators: less than (lt), greater than (gt), less than or equal to (le), and greater than or equal to (ge)
  • Lambda Operators: any (any), and all (all)
  • Conditional Operators: and (and), or (or)
  • Functions: starts with (startsWith), ends with (endsWith), and Contains (contains)

Microsoft also states in the documentation that support for the operators varies by the entity, and some properties support $filter only in advanced queries.

Some examples using the “Get-MgSecurityAlert” command are listed below, which all use the “eq” filter, with different ways of passing the values.

Working

# Standard Category Filter
Get-MgSecurityAlert `
	-Filter "Category eq 'ThreatManagement'"

# Standard Status Filter
Get-MgSecurityAlert `
	-Filter "Status eq 'newAlert'"

# Nested Query within "vendorInformation {}" object
Get-MgSecurityAlert `
	-Filter "vendorInformation/vendor eq 'Microsoft'"

# Nested Query within "vendorInformation {}" object
 Get-MgSecurityAlert `
	-Filter "vendorInformation/provider eq 'MCAS'"

# Standard ID Query
Get-MgSecurityAlert `
	-Filter "Id eq 'd84203d3-5d68-4376-ce00-08d97c32393a'"

# Nested Query within "userStates []" object
Get-MgSecurityAlert `
	-Filter "userStates/any(d:d/accountName eq 'admin')"

Failing

# Standard Category Filter Swapped Quotes around
Get-MgSecurityAlert `
	-Filter 'Status eq "newAlert"'

# Standard Title Filter with Spaces
Get-MgSecurityAlert `
	-Filter "Title eq 'Activity from infrequent country'"

# Standard ID Query using longer ID
Get-MgSecurityAlert `
	-Filter "Id eq 'c3d5b7f325f17eb9a7059288141e10a33cf03a55c3edc29a517aa904eceb2dc7'"

# Standard Alert ID Query
Get-MgSecurityAlert `
	-Filter "AlertID eq 'd84203d3-5d68-4376-ce00-08d97c32393a'"

# Standard CONTAINS Category Filter
Get-MgSecurityAlert `
	-Filter "Category contains 'Threat'"

# Standard NOT EQUAL Filter Returning All Rows not Filtered
Get-MgSecurityAlert `
	-Filter "Category ne 'ThreatManagement'"

# Standard ENDS WITH Filter
Get-MgSecurityAlert `
	-Filter "endsWith(Category,'Management')"

# Nested Query within "cloudAppStates []" object
Get-MgSecurityAlert `
	-Filter "cloudAppStates/any(d:d/destinationServiceName eq 'Microsoft Cloud App Security')"

However, the good news is that you can test these queries within Graph Explorer or use the “Invoke-MgGraphRequest” instead to retrieve the required details. 

WORKED: Standard Category Query

$alertslist = New-Object System.Collections.ArrayList
 
$graphversion = "beta"
$url = "https://graph.microsoft.com"
$endpoint = "security/alerts?`$filter="
$filter = "Category eq 'ThreatManagement'"
 
$body = @{}
 
$uri = "$url/$graphversion/$endpoint$filter"
  
$alerts = Invoke-MgGraphRequest `
    -Uri $uri `
    -Method GET `
    -Body $body
 
$alerts.value | ForEach-Object {
    $alertslist.Add(@{ `
        "ID"=$_.Id; `
        "Title"=$_.Title; `
        "Category"=$_.Category; `
        "Description"=$_.Description; `
        "Severity"=$_.Severity;
    }) `
}
 
$alertslist

WORKED: Nested Query within “cloudAppStates []” object

$alertslist = New-Object System.Collections.ArrayList
$graphversion = "beta"
$url = "https://graph.microsoft.com"
$endpoint = "security/alerts?`$filter="
$filter = "cloudAppStates/any(d:d/destinationServiceName eq 'Microsoft Cloud App Security')"
$body = @{}
 
$uri = "$url/$graphversion/$endpoint$filter"
 
$alerts = Invoke-MgGraphRequest `
    -Uri $uri `
    -Method GET `
    -Body $body

$alerts.value | ForEach-Object {
	Write-Host $_
    $alertslist.Add(@{ `
        "ID"=$_.Id; `
        "Title"=$_.Title; `
        "Category"=$_.Category; `
        "Description"=$_.Description; `
        "Severity"=$_.Severity;
    }) `
}

$alerts.value | ForEach-Object {
	Write-Host $_
}

$alertslist

Unfortunately, not all the queries work as expected, so they don’t work within Graph PowerShell.

FAILED: Standard Title Filter with Spaces

$alertslist = New-Object System.Collections.ArrayList
$graphversion = "beta"
$url = "https://graph.microsoft.com"
$endpoint = "security/alerts?`$filter="
$filter = "title eq 'Activity from infrequent country'"
$body = @{}
 
$uri = "$url/$graphversion/$endpoint$filter"
 
$alerts = Invoke-MgGraphRequest `
    -Uri $uri `
    -Method GET `
    -Body $body

$alerts.value | ForEach-Object {
    $alertslist.Add(@{ `
        "ID"=$_.Id; `
        "Title"=$_.Title; `
        "Category"=$_.Category; `
        "Description"=$_.Description; `
        "Severity"=$_.Severity;
    }) `
}

$alertslist

FAILED: Standard NOT EQUAL Filter

$alertslist = New-Object System.Collections.ArrayList
$graphversion = "beta"
$url = "https://graph.microsoft.com"
$endpoint = "security/alerts?`$filter="
$filter = "Category ne 'ThreatManagement'"
$body = @{}
 
$uri = "$url/$graphversion/$endpoint$filter"
 
$alerts = Invoke-MgGraphRequest `
    -Uri $uri `
    -Method GET `
    -Body $body

$alerts.value | ForEach-Object {
    $alertslist.Add(@{ `
        "ID"=$_.Id; `
        "Title"=$_.Title; `
        "Category"=$_.Category; `
        "Description"=$_.Description; `
        "Severity"=$_.Severity;
    }) `
}

$alertslist

FAILED: ENDS WITH Filter

$alertslist = New-Object System.Collections.ArrayList
$graphversion = "beta"
$url = "https://graph.microsoft.com"
$endpoint = "security/alerts?`$filter="
$filter = "endsWith(Category,'Management')"
$body = @{}
 
$uri = "$url/$graphversion/$endpoint$filter"
 
$alerts = Invoke-MgGraphRequest `
    -Uri $uri `
    -Method GET `
    -Body $body

$alerts.value | ForEach-Object {
    $alertslist.Add(@{ `
        "ID"=$_.Id; `
        "Title"=$_.Title; `
        "Category"=$_.Category; `
        "Description"=$_.Description; `
        "Severity"=$_.Severity;
    }) `
}

$alertslist

The good news is that you can utilize the “-debug” property and output what the command is using for the connection.

Get-MgSecurityAlert `
	-Filter "Title eq 'Activity from infrequent country'" `
	-Debug

The purpose of outlining some of these is not to say don’t use Graph PowerShell but to highlight that you need to utilize different approaches that are not the standard commands. If I have learned one thing over the past 20+ years of writing scripts in various programming languages, you need to be flexible and use what you can. Sometimes you can use the exact command, sometimes it will need to be a direct REST API call, and sometimes you write your own.

I am saying that Graph PowerShell is fantastic and goes a long way to giving you what you need. My only advice would be to be careful, as not all the filtering or searching options are consistent for each command. I am sure that will come soon, as Graph PowerShell continues to mature.