Execute Advanced Hunting Queries Using PowerShell

March 25, 2023
2 min read

Another quick post. This time we combine Advanced Hunting Kusto Query Language (KQL) queries and Microsoft PowerShell Graph SDK.

We will use the same Advanced Hunting Kusto Query Language (KQL) as before:

EmailEvents | summarize Recipients= make_list(RecipientEmailAddress) by Subject, NetworkMessageId | project Subject, Recipients, NetworkMessageId

The PowerShell is also mostly the same with a few changes.

# Connect to the Graph using the App registration details

Connect-MgGraph ` -ClientId "05c53143-7c86-48b8-ac78" ` -TenantId "4510da24-0f43-48d3-837d" ` -CertificateThumbprint "3F813D3DAC8E3613199359D23AEBA"

However, we need to adjust the App registration API permissions to include the following:

  • SecurityEvents.ReadWrite.All
  • ThreatHunting.Read.All

Remember, these permissions will also need admin consent.

Now for the PowerShell:


# Define the Query

$query = "EmailEvents | summarize Recipients = make_list(RecipientEmailAddress) by Subject, NetworkMessageId | project Subject, Recipients, NetworkMessageId"

# Create the JSON body

$body = @{    Query = $query } | ConvertTo-Json

# Invoke the Microsoft Graph API to run the hunting query

$result = Invoke-MgGraphRequest `    -Method POST `    -Uri "https://graph.microsoft.com/v1.0/security/runHuntingQuery" `    -Body $body

# Process the results and create rows for each item with the specified columns

$table = $result.results | ForEach-Object {    [PSCustomObject]@{        Subject             = $_.Subject        RecipientList       = $_.Recipients        NetworkMessageId    = $_.NetworkMessageId    } }

# Display the table

$table | Format-Table

Here is the full code:

Connect-MgGraph `
    -ClientId "<ClientId>" `
    -TenantId "<TenantId>" CertificateThumbprint`
    -CertificateThumbprint "<>"

$query = "EmailEvents
| summarize Recipients = make_list(RecipientEmailAddress) by Subject, 
| project Subject, Recipients, NetworkMessageId"

$body = @{
    Query = $query
} | ConvertTo-Json

$result = Invoke-MgGraphRequest `
    -Method POST `
    -Uri "https://graph.microsoft.com/v1.0/security/runHuntingQuery" `
    -Body $body

$table = $result.results | ForEach-Object {
        Subject             = $_.Subject
        RecipientList       = $_.Recipients
        NetworkMessageId    = $_.NetworkMessageId

$table | Format-Table

After executing this code will return the same values that the Kusto Query Language (KQL) returned within Advance Hunting. I hope this is helpful, happy hunting 🙂

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.