Microsoft Graph PowerShell Filtering Working and Failures

October 19, 2021
5 min read
Syndicated

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.

Liam Cleary

Liam Cleary

Liam began his career as a computer trainer. He quickly realized that programming, breaking and hacking were much more fun. Liam spent the next few years working within core infrastructure and security services. He is now the founder and owner of SharePlicity, a consulting company focusing on Microsoft 365 and Azure technology. His role within SharePlicity is to help organizations implement Microsoft 365 and Azure technology to enhance internal and external collaboration, document, and records management, automate business processes, and implement security controls and protection. He is a long-time Microsoft MVP and Microsoft Certified Trainer, focusing on architecture, security and crossing the boundary into software development. Over the past few years, his specialty has been security in Microsoft 365, Azure and its surrounding platforms. Liam also creates online training courses for Pluralsight, LinkedIn Learning and Cloud Academy, and he teaches multiple Microsoft certification courses for Opsgility and Microsoft. You can find him at user groups and conferences, teaching classes, offering advice, spending time in the community, teaching his kids how to code, raspberry PI programming, hacking the planet, building Lego robots, or coaching soccer. You may also find him running races in the dark, hiking, or mountain biking at breakneck speeds.