Functions/Get-GraphSecurityAlert.ps1

<#
.Synopsis
   Gets alerts in Microsoft Graph Security.
 
.DESCRIPTION
   Gets alerts in Microsoft Graph Security.
 
   Without parameters, Get-GraphSecurityAlert gets 100 alerts and associated properties. You can specify a particular alert to fetch a single alert's information or you can pull a list of activities based on the provided filters.
 
   There are multiple parameter sets:
 
.EXAMPLE
   Get-GraphSecurityAlert
 
    This will default grab the Top 100 alerts.
 
.EXAMPLE
   Get-GraphSecurityAlert -id D0ED9BD3-AB24-3E05-A4D3-171280CA3CB9
 
    This will get a single alert.
 
.EXAMPLE
   Get-GraphSecurityAlert -provider MCAS -severity high
 
    This will get all alerts from MCAS with high severity.
 
.FUNCTIONALITY
   Get-GraphSecurityAlert is intended to function as a mechanism for getting alerts using Microsoft Graph Security.
#>

function Get-GraphSecurityAlert {
    [cmdletbinding(DefaultParameterSetName = 'Default')]
    param
    (
        #Specifies the API Version
        [Parameter(ParameterSetName = 'Default', Mandatory = $false)]
        [Parameter(ParameterSetName = 'Fetch', Mandatory = $false)]
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateSet("v1.0", "Beta")]
        [string]$Version = "v1.0",

        # Fetches an activity object by its unique identifier.
        [Parameter(ParameterSetName = 'Fetch', Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string]$id,

        # Specifies the maximum number of results to retrieve
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateRange(1, 1000)]
        [int]$top = "100",

        # Specifies the number of records, from the beginning of the result set, to skip.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateRange(0, 5000)]
        [int]$skip = 0,

        # Returns the number of alerts to the user
        [Parameter(ParameterSetName = 'Count', Mandatory = $false)]
        [ValidateSet("true", "false")]
        [string]$count = "false",

        ##### OrderBy Param #####

        #Currently orderBy Ascending by default
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateSet("riskScore", "tags", "id",
            "azureTenantId", "activityGroupName", "assignedTo",
            "category", "closedDateTime", "comments",
            "confidence", "createdDateTime", "description",
            "detectionIds", "eventDateTime", "feedback",
            "lastModifiedDateTime", "recommendedActions", "severity",
            "sourceMaterials", "status", "title",
            "vendorInformation", "cloudAppStates", "fileStates",
            "hostStates", "malwareStates", "networkConnections",
            "processes", "registryKeyStates", "triggers",
            "userStates", "vulnerabilityStates")]
        [string]$orderBy = "none",

        #### OData Query Params #####

        # Provider generated/calculated risk score of the network connection. Recommended value range of 0-1, which equates to a percentage.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$riskScore,

        # Name or alias of the activity group (attacker) this alert is attributed to.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$activityGroupName,

        # Name of the analyst the alert is assigned to for triage, investigation, or remediation (supports update).
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$assignedTo,

        # Azure subscription ID, present if this alert is related to an Azure resource.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$azureSubscriptionId,

        # Azure Active Directory tenant ID. Required.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$azureTenantId,

        # Category of the alert (for example, credentialTheft, ransomware, etc.).
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$category,

        # Customer-provided comments on alert (for customer alert management) (supports update).
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string[]]$comments,

        # Confidence of the detection logic (percentage between 1-100).
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string[]]$confidence,

        # Set of alerts related to this alert entity (each alert is pushed to the SIEM as a separate record).
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string[]]$detectionIds,

        # Analyst feedback on the alert.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("unknown", "truePositive", "falsePositive", "begninPostive")]
        [string]$feedback = "none",

        # Alert severity - set by vendor/provider.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("unknown", "informational", "low", "medium", "high")]
        [string]$severity = "none",

        # Hyperlinks (URIs) to the source material related to the alert, for example, provider's user interface for alerts or log search, etc.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string[]]$sourceMaterials,

        # Alert lifecycle status (stage).
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("unknown", "newAlert", "inProgress", "resolved")]
        [string]$status = "none",

        # User-definable labels that can be applied to an alert and can serve as filter conditions (for example "HVA", "SAW", etc.) (supports update).
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string[]]$tags,

        # Alert title. Required.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript( { $_.Length -ge 5 })]
        [string]$title,

        ####### Vendor Information ######

        # Specific provider (product/service - not vendor company); for example, WindowsDefenderATP.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$provider,

        # Name of the alert vendor (for example, Microsoft, Dell, FireEye). Required
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$vendor,

        ####### User State Information ######

        # AAD User object identifier (GUID) - represents the physical/multi-account user entity.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$aadUserId,

        # Account name of user account (without Active Directory domain or DNS domain) - (also called mailNickName). Case-Sensitive
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$accountName,

        # For email-related alerts - user account's email 'role'.
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$emailRole,

        # User sign-in name - internet format: (user account name)@(user account DNS domain name).
        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$userPrincipalName,

        ####### Host Security State Information ######

        <# Needs further testing, omitted for release 1.0
 
            # # Host FQDN (Fully Qualified Domain Name) (for example, machine.company.com).
            # [Parameter(ParameterSetName='List', Mandatory=$false)]
            # [ValidateNotNullOrEmpty()]
            # [string]$FQDN,
 
        #>


        <# Needs further testing, omitted for release 1.0
 
            # # Private (not routable) IPv4 or IPv6 address (see RFC 1918) at the time of the alert.
            # [Parameter(ParameterSetName='List', Mandatory=$false)]
            # [ValidateNotNullOrEmpty()]
            # [string]$privateIpAddress,
 
        #>


        <# Needs further testing, omitted for release 1.0
 
            # # Publicly routable IPv4 or IPv6 address (see RFC 1918) at time of the alert.
            # [Parameter(ParameterSetName='List', Mandatory=$false)]
            # [ValidateNotNullOrEmpty()]
            # [string]$publicIpAddress,
 
        #>


        # ####### File Security State Information ######

        <# Needs further testing, omitted for release 1.0
 
            # # File name (without path).
            # [Parameter(ParameterSetName='List', Mandatory=$false)]
            # [ValidateNotNullOrEmpty()]
            # [string]$fileName,
 
        #>


        ####### Date Time Params ######

        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$eventDateTimeAfter = "",

        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$eventDateTimeBefore = "",

        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$createdDateTimeAfter = "",

        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$createdDateTimeBefore = "",

        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$closedDateTimeAfter = "",

        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$closedDateTimeBefore = "",

        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$lastModifiedDateTimeAfter = "",

        [Parameter(ParameterSetName = 'List', Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$lastModifiedDateTimeBefore = ""
    )

    Begin {
        Try { Test-GraphSecurityAuthToken }
        Catch { Throw $_ }
    }
    Process {
        # Fetch mode should happen once for each item from the pipeline, so it goes in the 'Process' block
        if ($PSCmdlet.ParameterSetName -eq 'Fetch') {
            try {
                # Fetch the item by its id
                $resource = "security/alerts/$id"
                $uri = "https://graph.microsoft.com/$Version/$($resource)"
                $response = Invoke-RestMethod -Uri $uri -Headers $GraphSecurityAuthHeader -Method Get
                Write-Verbose "Calling: $uri"
            }
            catch {
                $ex = $_.Exception
                $errorResponse = $ex.Response.GetResponseStream()
                $reader = New-Object System.IO.StreamReader($errorResponse)
                $reader.BaseStream.Position = 0
                $reader.DiscardBufferedData()
                $responseBody = $reader.ReadToEnd();
                Write-Verbose "Response content:`n$responseBody"
                Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"

                break
            }
            $response
        }
    }
    End {

        # After all things have been processed in pipeline
        if ($PSCmdlet.ParameterSetName -eq 'List' -or $PSCmdlet.ParameterSetName -eq 'Default' -and $PSCmdlet.ParameterSetName -ne 'Fetch') {

            # List mode logic only needs to happen once, so it goes in the 'End' block for efficiency

            $body = "?`$top=$top&`$filter="

            # Simple filters

            if ($category) { $body += "`category+eq+`'$category`' and " }
            if ($severity -ne "none") { $body += "severity+eq+`'$severity`' and " }
            if ($status -ne "none") { $body += "status+eq+`'$status`' and " }
            if ($title) { $body += "title+eq+`'$title`' and " }
            if ($azureTenantId) { $body += "azureTenantId+eq+`'$azureTenantId`' and " }
            if ($riskScore) { $body += "riskScore+eq+`'$riskScore`' and " }
            if ($tags) { $body += "tags+eq+`'$tags`' and " }
            if ($azureSubscriptionId) { $body += "azureSubscriptionId+eq+`'$azureSubscriptionId`' and " }
            if ($activityGroupName) { $body += "activityGroupName+eq+`'$activityGroupName`' and " }
            if ($assignedTo) { $body += "assignedTo+eq+`'$assignedTo`' and " }
            if ($confidence) { $body += "confidence+eq+`'$confidence`' and " }
            if ($detectionIds) { $body += "detectionIds+eq+`'$detectionIds`' and " }
            if ($sourceMaterials) { $body += "sourceMaterials+eq+`'$sourceMaterials`' and " }

            ####### User State Information ######

            if ($aadUserId) { $body += "userStates/any(d:d/aadUserId+eq+`'$aadUserId`') and " }
            if ($accountName) { $body += "userStates/any(d:d/accountName+eq+`'$accountName`') and " }
            if ($userPrincipalName) { $body += "userStates/any(d:d/userPrincipalName+eq+`'$userPrincipalName`') and " }
            if ($domainName) { $body += "userStates/any(d:d/domainName+eq+`'$domainName`') and " }


            <# Needs further testing, omitted for release 1.0
 
                # if ($FQDN){$body += "hostSecurityState/FQDN+eq+`'$FQDN`'&"}
 
            #>

            <# Needs further testing, omitted for release 1.0
 
                # if ($privateIpAddress){$body += "hostSecurityState/privateIpAddress+eq+`'$privateIpAddress`'&"}
 
            #>

            <# Needs further testing, omitted for release 1.0
 
                # if ($publicIpAddress){$body += "hostSecurityState/publicIpAddress+eq+`'$publicIpAddress`'&"}
 
            #>


            ####### File Security State Information ######
            <# Needs further testing, omitted for release 1.0
 
                # if ($filName){$body += "fileSecurityState/name+eq+`'$fileName`'&"}
 
            #>


            if ($eventDateTimeAfter) {
                $eventDateTimeAfter = (Get-Date -Date $eventDateTimeAfter -Format "yyyy-MM-ddTHH:mm:ssZ")
                $body += "eventDateTime+gt+$eventDateTimeAfter and "
            }

            if ($eventDateTimeBefore) {
                $eventDateTimeBefore = (Get-Date -Date $eventDateTimeBefore -Format "yyyy-MM-ddTHH:mm:ssZ")
                $body += "eventDateTime+lt+$eventDateTimeBefore and "
            }

            if ($createdDateTimeAfter) {
                $createdDateTimeAfter = (Get-Date -Date $createdDateTimeAfter -Format "yyyy-MM-ddTHH:mm:ssZ")
                $body += "createdDateTime+gt+$createdDateTimeAfter and "
            }

            if ($createdDateTimeBefore) {
                $createdDateTimeBefore = (Get-Date -Date $createdDateTimeBefore -Format "yyyy-MM-ddTHH:mm:ssZ")
                $body += "createdDateTime+lt+$createdDateTimeBefore and "
            }

            if ($closedDateTimeAfter) {
                $closedDateTimeAfter = (Get-Date -Date $closedDateTimeAfter -Format "yyyy-MM-ddTHH:mm:ssZ")
                $body += "closedDateTime+gt+$closedDateTimeAfter and "
            }

            if ($closedDateTimeBefore) {
                $closedDateTimeBefore = (Get-Date -Date $closedDateTimeBefore -Format "yyyy-MM-ddTHH:mm:ssZ")
                $body += "closedDateTime+lt+$closedDateTimeBefore and "
            }

            if ($lastModifiedDateTimeAfter) {
                $lastModifiedDateTimeAfter = (Get-Date -Date $lastModifiedDateTimeAfter -Format "yyyy-MM-ddTHH:mm:ssZ")
                $body += "lastModifiedDateTime+gt+$lastModifiedDateTimeAfter and "
            }

            if ($lastModifiedDateTimeBefore) {
                $lastModifiedDateTimeBefore = (Get-Date -Date $lastModifiedDateTimeBefore -Format "yyyy-MM-ddTHH:mm:ssZ")
                $body += "lastModifiedDateTime+lt+$lastModifiedDateTimeBefore and "
            }

            if ($provider) { $body += "vendorInformation/provider+eq+`'$provider`' and " }
            if ($vendor) { $body += "vendorInformation/vendor+eq+`'$vendor`' and " }

            $body = $body -replace ' and $', ''

            if ($Skip) { $body += "&`$skip=$Skip" }
            if ($orderBy -ne "none") { $body += "&`$orderBy=$orderBy" }

            Write-Verbose "URI Body: $body"

            #region ----------------------------API CALL----------------------------

            Write-Verbose "In the List"
            try {
                Write-Verbose "Trying List"
                $resource = "security/alerts/"
                $uri = "https://graph.microsoft.com/$Version/$($resource)$body"

                $response = Invoke-RestMethod -Uri $uri -Headers $GraphSecurityAuthHeader -Method Get

                Write-Verbose "Trying List $response"
            }
            catch {
                $ex = $_.Exception
                $errorResponse = $ex.Response.GetResponseStream()
                $reader = New-Object System.IO.StreamReader($errorResponse)
                $reader.BaseStream.Position = 0
                $reader.DiscardBufferedData()
                $responseBody = $reader.ReadToEnd();
                Write-Verbose "Response content:`n$responseBody"
                Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
                break
            }
            $response.value
        }

    }
}