├── doc.md ├── MicrosoftGraphSecurity.psd1 ├── Functions ├── Select-GraphSecurityAppId.ps1 ├── Select-GraphSecurityUsername.ps1 ├── Install-GraphSecurityAADModule.ps1 ├── Test-GraphSecurityAuthToken.ps1 ├── Get-GraphSecuritySecureScore.ps1 ├── Get-GraphSecurityCredential.ps1 ├── Get-GraphSecurityAuthToken.ps1 ├── Set-GraphSecurityAlert.ps1 └── Get-GraphSecurityAlert.ps1 ├── LICENSE.txt ├── MicrosoftGraphSecurity.psm1 ├── .vscode └── launch.json ├── Docs ├── Get-GraphSecuritySecureScore.md ├── Get-GraphSecurityCredential.md ├── Set-GraphSecurityAlert.md └── Get-GraphSecurityAlert.md ├── SECURITY.md ├── README.md └── .gitignore /doc.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MicrosoftGraphSecurity.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/MicrosoftGraphSecurity/HEAD/MicrosoftGraphSecurity.psd1 -------------------------------------------------------------------------------- /Functions/Select-GraphSecurityAppId.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Internal function to get the AppId for the Authentication Token for Microsoft Graph Security. 4 | 5 | .DESCRIPTION 6 | Gets the AppId for the Authentication Token for Microsoft Graph Security. 7 | 8 | .EXAMPLE 9 | Select-GraphSecurityAppId 10 | 11 | .FUNCTIONALITY 12 | Select-GraphSecurityAppId is intended as an internal function to get the AppId for Authentication Token. 13 | #> 14 | 15 | function Select-GraphSecurityAppId { 16 | 17 | #Check for the Credential 18 | If ($Global:GraphSecurityCredential) { 19 | 20 | $Global:GraphSecurityCredential.GetNetworkCredential().Password 21 | } 22 | 23 | Else { 24 | 25 | #Write-Error 'No AppId available. Please check the AppId of the supplied credential' -ErrorAction Stop 26 | Get-GraphSecurityCredential 27 | 28 | $Global:GraphSecurityCredential.GetNetworkCredential().Password 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Functions/Select-GraphSecurityUsername.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Internal function to get the username for the Authentication Token for Microsoft Graph Security. 4 | 5 | .DESCRIPTION 6 | Gets the username for the Authentication Token for Microsoft Graph Security. 7 | 8 | .EXAMPLE 9 | Select-GraphSecurityUsername 10 | 11 | .FUNCTIONALITY 12 | Select-GraphSecurityUsername is intended as an internal function to get the username for Authentication Token. 13 | #> 14 | 15 | function Select-GraphSecurityUsername { 16 | 17 | If ($Global:GraphSecurityCredential) { 18 | 19 | $Global:GraphSecurityCredential.GetNetworkCredential().Username 20 | 21 | } 22 | 23 | Else { 24 | 25 | #Write-Error 'No username available. Please check the username of the supplied credential' -ErrorAction Stop 26 | 27 | Get-GraphSecurityCredential 28 | 29 | $Global:GraphSecurityCredential.GetNetworkCredential().Username 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Functions/Install-GraphSecurityAADModule.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Internal function to install the AAD Module for Microsoft Graph Security. 4 | 5 | .DESCRIPTION 6 | Installs the AAD Module for Microsoft Graph Security. 7 | 8 | .EXAMPLE 9 | Install-GraphSecurityAADModule 10 | 11 | .FUNCTIONALITY 12 | Install-GraphSecurityAADModule is intended as an internal function to install the AAD Module. 13 | #> 14 | 15 | function Install-GraphSecurityAADModule { 16 | 17 | [CmdletBinding()] 18 | 19 | #Check for Admin Privleges 20 | $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) 21 | 22 | if (-not ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))) { 23 | 24 | #No Admin, install to current user 25 | Write-Warning -Message "Can not install AAD Module. You are not running as Administrator" 26 | 27 | Write-Warning -Message "Installing AAD Module to Current User Scope" 28 | 29 | Install-Module AzureAD -Scope CurrentUser -Force 30 | } 31 | 32 | Else { 33 | 34 | #Admin, install to all users 35 | Install-Module AzureAD -Force 36 | 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /MicrosoftGraphSecurity.psm1: -------------------------------------------------------------------------------- 1 | #----------------------------Include functions--------------------------- 2 | # KUDOS to the chocolatey project for the basis of this code 3 | 4 | # get the path of where the module is saved (if module is at c:\myscripts\module.psm1, then c:\myscripts\) 5 | $mypath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Definition) 6 | 7 | #find all the ps1 files in the Functions subfolder 8 | Resolve-Path -Path $mypath\Functions\*.ps1 | ForEach-Object -Process { 9 | . $_.ProviderPath 10 | } 11 | 12 | #----------------------------Exports--------------------------- 13 | # Cmdlets to export (must be exported as functions, not cmdlets) - This array format can be copied directly to the manifest as the 'FunctionsToExport' value 14 | $ExportedCommands = @( 15 | 'Get-GraphSecurityAlert', 16 | 'Get-GraphSecurityCredential', 17 | 'Get-GraphSecuritySecureScore', 18 | 'Set-GraphSecurityAlert') 19 | $ExportedCommands | ForEach-Object {Export-ModuleMember -Function $_} 20 | 21 | # Vars to export (must be exported here, even if also included in the module manifest in 'VariablesToExport' 22 | Export-ModuleMember -Variable GraphSecurityCredential 23 | Export-ModuleMember -Variable GraphSecurityAuthToken 24 | 25 | # Aliases to export 26 | Export-ModuleMember -Alias * 27 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "PowerShell", 9 | "request": "launch", 10 | "name": "PowerShell Launch Current File", 11 | "script": "${file}", 12 | "args": [], 13 | "cwd": "${file}" 14 | }, 15 | { 16 | "type": "PowerShell", 17 | "request": "launch", 18 | "name": "PowerShell Launch Current File in Temporary Console", 19 | "script": "${file}", 20 | "args": [], 21 | "cwd": "${file}", 22 | "createTemporaryIntegratedConsole": true 23 | }, 24 | { 25 | "type": "PowerShell", 26 | "request": "launch", 27 | "name": "PowerShell Launch Current File w/Args Prompt", 28 | "script": "${file}", 29 | "args": [ 30 | "${command:SpecifyScriptArgs}" 31 | ], 32 | "cwd": "${file}" 33 | }, 34 | { 35 | "type": "PowerShell", 36 | "request": "attach", 37 | "name": "PowerShell Attach to Host Process", 38 | "processId": "${command:PickPSHostProcess}", 39 | "runspaceId": 1 40 | }, 41 | { 42 | "type": "PowerShell", 43 | "request": "launch", 44 | "name": "PowerShell Interactive Session", 45 | "cwd": "" 46 | } 47 | ] 48 | } -------------------------------------------------------------------------------- /Docs/Get-GraphSecuritySecureScore.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: MicrosoftGraphSecurity-help.xml 3 | Module Name: MicrosoftGraphSecurity 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-GraphSecuritySecureScore 9 | 10 | ## SYNOPSIS 11 | Gets secure scores in Microsoft Graph Security. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Get-GraphSecuritySecureScore [[-top] ] [[-Version] ] [] 17 | ``` 18 | 19 | ## DESCRIPTION 20 | Gets secure score in Microsoft Graph Security. 21 | 22 | Without parameters, Get-GraphSecuritySecureScore gets 100 secure scores and associated properties. 23 | 24 | ## EXAMPLES 25 | 26 | ### EXAMPLE 1 27 | ``` 28 | Get-GraphSecuritySecureScore 29 | ``` 30 | 31 | This will default grab the Top 100 secure scores. 32 | 33 | ## PARAMETERS 34 | 35 | ### -top 36 | Specifies the maximum number of results to retrieve 37 | 38 | ```yaml 39 | Type: String 40 | Parameter Sets: (All) 41 | Aliases: 42 | 43 | Required: False 44 | Position: 1 45 | Default value: 100 46 | Accept pipeline input: False 47 | Accept wildcard characters: False 48 | ``` 49 | 50 | ### -Version 51 | Specifies the API Version 52 | 53 | ```yaml 54 | Type: String 55 | Parameter Sets: (All) 56 | Aliases: 57 | 58 | Required: False 59 | Position: 2 60 | Default value: Beta 61 | Accept pipeline input: False 62 | Accept wildcard characters: False 63 | ``` 64 | 65 | ### CommonParameters 66 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). 67 | 68 | ## INPUTS 69 | 70 | ## OUTPUTS 71 | 72 | ## NOTES 73 | 74 | ## RELATED LINKS 75 | -------------------------------------------------------------------------------- /Functions/Test-GraphSecurityAuthToken.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Internal function to test if the current sessions has a Authentication Token for Microsoft Graph Security. 4 | 5 | .DESCRIPTION 6 | Tests if the current sessions has a Authentication Token for Microsoft Graph Security. 7 | 8 | .EXAMPLE 9 | Test-GraphSecurityAuthToken 10 | 11 | .FUNCTIONALITY 12 | Test-GraphSecurityAuthToken is intended as an internal function to test for Authentication Token. 13 | #> 14 | 15 | function Test-GraphSecurityAuthToken { 16 | 17 | # Checking if authToken exists before running authentication 18 | if ($global:GraphSecurityauthHeader) { 19 | 20 | # Setting DateTime to Universal time to work in all timezones 21 | $DateTime = (Get-Date).ToUniversalTime() 22 | 23 | # If the authToken exists checking when it expires 24 | $TokenExpires = ($GraphSecurityauthHeader.ExpiresOn.datetime - $DateTime).Minutes 25 | 26 | if ($TokenExpires -le 0) { 27 | 28 | #Token is expired, check for UserName and AppId, and go get a token 29 | Write-Warning "Authentication Token expired $TokenExpires minutes ago" 30 | 31 | Try { $Username = Select-GraphSecurityUsername } 32 | Catch { Throw $_ } 33 | 34 | Try { $AppId = Select-GraphSecurityAppId } 35 | Catch { Throw $_ } 36 | 37 | Write-Warning "Refreshing Auth Token" 38 | Get-GraphSecurityAuthToken 39 | 40 | } 41 | } 42 | 43 | 44 | # Authentication doesn't exist, calling Get-GraphSecurityAuthToken function 45 | 46 | else { 47 | 48 | Try { $Username = Select-GraphSecurityUsername } 49 | Catch { Throw $_ } 50 | 51 | Try { $AppId = Select-GraphSecurityAppId } 52 | Catch { Throw $_ } 53 | 54 | Get-GraphSecurityAuthToken 55 | 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /Functions/Get-GraphSecuritySecureScore.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Gets secure scores in Microsoft Graph Security. 4 | 5 | .DESCRIPTION 6 | Gets secure score in Microsoft Graph Security. 7 | 8 | Without parameters, Get-GraphSecuritySecureScore gets 100 secure scores and associated properties. 9 | 10 | .EXAMPLE 11 | Get-GraphSecuritySecureScore 12 | 13 | This will default grab the Top 100 secure scores. 14 | 15 | .FUNCTIONALITY 16 | Get-GraphSecuritySecureScore is intended to function as a mechanism for getting secure scores using Microsoft Graph Security. 17 | #> 18 | function Get-GraphSecuritySecureScore { 19 | [CmdletBinding()] 20 | Param 21 | ( 22 | # Specifies the maximum number of results to retrieve 23 | [Parameter(Mandatory = $false)] 24 | [string]$top = "100", 25 | 26 | #Specifies the API Version 27 | [Parameter(Mandatory = $false)] 28 | [ValidateSet("v1", "beta")] 29 | [string]$Version = "beta" 30 | ) 31 | Begin { 32 | Try { Test-GraphSecurityAuthToken } 33 | Catch { Throw $_ } 34 | } 35 | Process { 36 | if ($Version -eq "beta") { 37 | $Resource = "security/secureScores?`$top=$top" 38 | try { 39 | if ($Version -eq "beta") { 40 | $uri = "https://graph.microsoft.com/$Version/$($resource)" 41 | } 42 | Else { 43 | #$uri = "https://graph.microsoft.com/$Version.0/$($resource)" 44 | Write-Error "Secure Score is not yet implemented in v1.0 API" 45 | break 46 | } 47 | (Invoke-RestMethod -Uri $uri -Headers $GraphSecurityAuthHeader -Method Get).value 48 | } 49 | catch { 50 | $ex = $_.Exception 51 | $errorResponse = $ex.Response.GetResponseStream() 52 | $reader = New-Object System.IO.StreamReader($errorResponse) 53 | $reader.BaseStream.Position = 0 54 | $reader.DiscardBufferedData() 55 | $responseBody = $reader.ReadToEnd(); 56 | Write-Verbose "Response content:`n$responseBody" 57 | Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)" 58 | 59 | break 60 | } 61 | } 62 | Else { 63 | 64 | 65 | } 66 | } 67 | End { 68 | #Do nothing 69 | } 70 | } -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project has adopted the [Microsoft Open Source Code of Conduct](http://microsoft.github.io/codeofconduct). For more information see the [Code of Conduct FAQ](http://microsoft.github.io/codeofconduct/faq.md) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 2 | 3 | # Microsoft Graph Security PowerShell Module [ Unofficial] 4 | Welcome to the Unofficial Microsoft Graph Security PowerShell module! 5 | 6 | This module is a collection of easy-to-use cmdlets and functions designed to make it easy to interface with the Microsoft Graph Security API. 7 | 8 | Why is it unofficial, you ask? Even though this module was designed by Microsoft employees, it is NOT a formal part of the Graph Security API product and you will not be able to get support through standard Microsoft channels. That said, if you have problems or questions, please open an issue here on this Github repo. The authors will be more than happy to help. 9 | 10 | 11 | ## Prerequisites 12 | 13 | To get value from this module you must... 14 | 15 | 16 | ...have PowerShell v5+ (comes standard on Windows 10) 17 | 18 | ...have configured authorization for access by registering an application. See [Authorization and the Microsoft Graph Security API](https://docs.microsoft.com/en-us/graph/security-authorization#register-an-application-in-the-azure-ad-v20-endpoint) 19 | 20 | ### App Registration Settings 21 | 22 | Register an application with Azure AD with the following 23 | - **Authentication** 24 | - Select the Suggested Redirect URI to be `urn:ietf:wg:oauth:2.0:oob` 25 | - Select Implicit grant issued by the authorization endpoint `Access Tokens` 26 | - **API Permissions** 27 | - Add Microsoft Graph Delegated Permissions `SecurityEvents.Read.Al`l and/or `SecurityEvents.ReadWrite.All` 28 | 29 | 30 | ## Getting Started 31 | 32 | To get started with the module, open your PowerShell terminal as an administrator and install the module from the PSGallery by running this simple command: 33 | ``` 34 | Install-Module MicrosoftGraphSecurity 35 | ``` 36 | If this is your first time installing a module, you will get prompted to install the Nuget Package Provider. Nuget is the Package/Module manager used by the PSGallery repository. 37 | 38 | ## Contributing 39 | 40 | Apologies, we are not currently opening up this project for contribution outside of our existing team. This may change in the future if there is enough interest. 41 | 42 | ## Authors 43 | 44 | 45 | * **Anisha Gupta** - *Co-Lead Dev* - [LinkedIn](https://www.linkedin.com/in/ani6gup/) 46 | * **Nicholas DiCola** - *Co-Lead Dev* - [LinkedIn](https://linkedin.com/in/ndicola/) 47 | * **Mike Kassis** - *Test Design* - [LinkedIn](www.linkedin.com/in/mrkassis) 48 | 49 | See also the list of [contributors](https://github.com/your/project/contributors) who participated in this project. 50 | 51 | ## License 52 | 53 | This project has adopted the [Microsoft Open Source Code of Conduct](http://microsoft.github.io/codeofconduct). For more information see the [Code of Conduct FAQ](http://microsoft.github.io/codeofconduct/faq.md) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 54 | -------------------------------------------------------------------------------- /Docs/Get-GraphSecurityCredential.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: MicrosoftGraphSecurity-help.xml 3 | Module Name: MicrosoftGraphSecurity 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-GraphSecurityCredential 9 | 10 | ## SYNOPSIS 11 | Gets a username and AppID to be used by other Microsoft Graph Security module cmdlets. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Get-GraphSecurityCredential [[-Username] ] [-PassThru] [] 17 | ``` 18 | 19 | ## DESCRIPTION 20 | Get-GraphSecurityCredential imports a username and AppId to be used by other Microsoft Graph Security module cmdlets. 21 | 22 | When using Get-GraphSecurityCredential you will be prompted to provide your Azure AD username (UPN) and AppId. 23 | 24 | Get-GraphSecurityCredential takes the username and AppId and stores them in a special global session variable called $GraphSecurityCredential. 25 | 26 | Get-GraphSecurityAuthToken references that special global variable to get an authentication token. 27 | 28 | See the examples section for ways to automate setting your Microsoft Graph Security credentials for the session. 29 | 30 | ## EXAMPLES 31 | 32 | ### EXAMPLE 1 33 | ``` 34 | Get-GraphSecurityCredential 35 | ``` 36 | 37 | This prompts the user to enter both their username as well as their password. 38 | 39 | Username = username (Example: Nicholas@contoso.com) 40 | Password = AppId (Example: 64407e7c-8522-417f-a003-f69ad0b1a89b) 41 | 42 | C:\\\>$GraphSecurityCredential 43 | 44 | To verify your credentials are set in the current session, run the above command. 45 | 46 | UserName Password 47 | -------- -------- 48 | nicholas@contoso.com System.Security.SecureString 49 | 50 | ### EXAMPLE 2 51 | ``` 52 | Get-GraphSecurityCredential -PassThru | Export-CliXml C:\Users\Nicholas\MyGraphSecurityCred.credential -Force 53 | ``` 54 | 55 | By specifying the -PassThru switch parameter, this will put the $GraphSecurityCredential into the pipeline which can be exported to a .credential file that will store the username and encrypted version of the AppId in a file. 56 | 57 | We can use this newly created .credential file to automate setting our credentials in the session by adding an import command to our profile. 58 | 59 | C:\\\>notepad $profile 60 | 61 | The above command will open our PowerShell profile, which is a set of commands that will run when we start a new session. 62 | By default it is empty. 63 | 64 | $GraphSecurityCredential = Import-Clixml "C:\Users\Nicholas\MyGraphSecurityCred.credential" 65 | 66 | By adding the above line to our profile and save, the next time we open a new PowerShell session, the credential file will automatically be imported into the $GraphSecurityCredential which allows us to use other cmdlets without running Get-GraphSecurityCredential at the start of the session. 67 | 68 | ## PARAMETERS 69 | 70 | ### -Username 71 | Specifies the username 72 | 73 | ```yaml 74 | Type: String 75 | Parameter Sets: (All) 76 | Aliases: 77 | 78 | Required: False 79 | Position: 1 80 | Default value: None 81 | Accept pipeline input: False 82 | Accept wildcard characters: False 83 | ``` 84 | 85 | ### -PassThru 86 | Specifies that the credential should be returned into the pipeline for further processing. 87 | 88 | ```yaml 89 | Type: SwitchParameter 90 | Parameter Sets: (All) 91 | Aliases: 92 | 93 | Required: False 94 | Position: Named 95 | Default value: False 96 | Accept pipeline input: False 97 | Accept wildcard characters: False 98 | ``` 99 | 100 | ### CommonParameters 101 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). 102 | 103 | ## INPUTS 104 | 105 | ## OUTPUTS 106 | 107 | ### System.Management.Automation.PSCredential 108 | ## NOTES 109 | 110 | ## RELATED LINKS 111 | -------------------------------------------------------------------------------- /Functions/Get-GraphSecurityCredential.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Gets a username and AppID to be used by other Microsoft Graph Security module cmdlets. 4 | .DESCRIPTION 5 | Get-GraphSecurityCredential imports a username and AppId to be used by other Microsoft Graph Security module cmdlets. 6 | 7 | When using Get-GraphSecurityCredential you will be prompted to provide your Azure AD username (UPN) and AppId. 8 | 9 | Get-GraphSecurityCredential takes the username and AppId and stores them in a special global session variable called $GraphSecurityCredential. 10 | 11 | Get-GraphSecurityAuthToken references that special global variable to get an authentication token. 12 | 13 | See the examples section for ways to automate setting your Microsoft Graph Security credentials for the session. 14 | 15 | .EXAMPLE 16 | Get-GraphSecurityCredential 17 | 18 | This prompts the user to enter both their username as well as their password. 19 | 20 | Username = username (Example: Nicholas@contoso.com) 21 | Password = AppId (Example: 64407e7c-8522-417f-a003-f69ad0b1a89b) 22 | 23 | C:\>$GraphSecurityCredential 24 | 25 | To verify your credentials are set in the current session, run the above command. 26 | 27 | UserName Password 28 | -------- -------- 29 | nicholas@contoso.com System.Security.SecureString 30 | 31 | .EXAMPLE 32 | Get-GraphSecurityCredential -PassThru | Export-CliXml C:\Users\Nicholas\MyGraphSecurityCred.credential -Force 33 | 34 | By specifying the -PassThru switch parameter, this will put the $GraphSecurityCredential into the pipeline which can be exported to a .credential file that will store the username and encrypted version of the AppId in a file. 35 | 36 | We can use this newly created .credential file to automate setting our credentials in the session by adding an import command to our profile. 37 | 38 | C:\>notepad $profile 39 | 40 | The above command will open our PowerShell profile, which is a set of commands that will run when we start a new session. By default it is empty. 41 | 42 | $GraphSecurityCredential = Import-Clixml "C:\Users\Nicholas\MyGraphSecurityCred.credential" 43 | 44 | By adding the above line to our profile and save, the next time we open a new PowerShell session, the credential file will automatically be imported into the $GraphSecurityCredential which allows us to use other cmdlets without running Get-GraphSecurityCredential at the start of the session. 45 | 46 | .FUNCTIONALITY 47 | Get-GraphSecurityCredential is intended to import the username and password into a global session variable to allow Get-GraphSecurityAuthToken to request an authentication token. 48 | #> 49 | 50 | function Get-GraphSecurityCredential { 51 | 52 | [CmdletBinding()] 53 | 54 | [OutputType([System.Management.Automation.PSCredential])] 55 | 56 | Param 57 | ( 58 | 59 | # Specifies the username 60 | [Parameter(Mandatory = $false)] 61 | [string]$Username, 62 | 63 | # Specifies that the credential should be returned into the pipeline for further processing. 64 | [Parameter(Mandatory = $false)] 65 | [switch]$PassThru 66 | 67 | ) 68 | Process { 69 | 70 | # If username is specified, prompt for password token and get it all into a global variable 71 | If ($Username) { 72 | [System.Management.Automation.PSCredential]$global:GraphSecurityCredential = Get-Credential -UserName $Username -Message "Enter your AppId in the password box" 73 | } 74 | 75 | # Else, prompt for both the username and password and get it all into a global variable 76 | Else { 77 | [System.Management.Automation.PSCredential]$global:GraphSecurityCredential = Get-Credential -Message "Enter your username and AppId" 78 | } 79 | 80 | # If -PassThru is specified, write the credential object to the pipeline (the global variable will also be exported to the calling session with Export-ModuleMember) 81 | If ($PassThru) { 82 | $GraphSecurityCredential 83 | } 84 | 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /Docs/Set-GraphSecurityAlert.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: MicrosoftGraphSecurity-help.xml 3 | Module Name: MicrosoftGraphSecurity 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Set-GraphSecurityAlert 9 | 10 | ## SYNOPSIS 11 | Sets the status of alerts in Microsoft Graph Security. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Set-GraphSecurityAlert [[-id] ] [[-Version] ] [[-assignedTo] ] [-Closed] [-Open] 17 | [[-closedDateTime] ] [[-comments] ] [[-feedback] ] [[-Status] ] 18 | [[-Tags] ] [] 19 | ``` 20 | 21 | ## DESCRIPTION 22 | Sets the status of alerts in Microsoft Graph Security. 23 | 24 | There are multiple parameter: 25 | 26 | assignedTo: Used for setting the name of the analyst the alert is assigned to for triage, investigation, or remediation. 27 | closed: Used to close the alert \[default is no\] 28 | closedDateTime: Time at which the alert was closed. 29 | \[default is current date and time\] 30 | comments: Analyst comments on the alert. 31 | feedback: Analyst feedback on the alert. 32 | Possible values are: unknown, truePositive, falsePositive, benignPositive. 33 | status: Alert lifecycle status (stage). 34 | Possible values are: unknown, newAlert, inProgress, resolved. 35 | tags: User-definable labels that can be applied to an alert and can serve as filter conditions. 36 | 37 | An alert identity is always required to be specified either explicity or implicitly from the pipeline. 38 | 39 | ## EXAMPLES 40 | 41 | ### EXAMPLE 1 42 | ``` 43 | Set-GraphSecurityAlert -Id D0ED9BD3-AB24-3E05-A4D3-171280CA3CB9 -Status resolved -Feedback truePositive 44 | ``` 45 | 46 | This marks a single specified alert as 'resolved' and as a 'truePositive'. 47 | 48 | ### EXAMPLE 2 49 | ``` 50 | Get-GraphSecurityAlert -Id D0ED9BD3-AB24-3E05-A4D3-171280CA3CB9 | Set-GraphSecurityAlert -Status inProgress -Assignedto joe@contoso.com 51 | ``` 52 | 53 | This will set the status of the specified alert as "inProgress" and who is working it "joe@contoso.com". 54 | 55 | ## PARAMETERS 56 | 57 | ### -id 58 | Specifies the alert id 59 | 60 | ```yaml 61 | Type: String 62 | Parameter Sets: (All) 63 | Aliases: 64 | 65 | Required: False 66 | Position: 1 67 | Default value: None 68 | Accept pipeline input: True (ByValue) 69 | Accept wildcard characters: False 70 | ``` 71 | 72 | ### -Version 73 | Specifies the API Version 74 | 75 | ```yaml 76 | Type: String 77 | Parameter Sets: (All) 78 | Aliases: 79 | 80 | Required: False 81 | Position: 2 82 | Default value: V1 83 | Accept pipeline input: False 84 | Accept wildcard characters: False 85 | ``` 86 | 87 | ### -assignedTo 88 | Sets the owner of the alert 89 | 90 | ```yaml 91 | Type: String 92 | Parameter Sets: (All) 93 | Aliases: 94 | 95 | Required: False 96 | Position: 3 97 | Default value: None 98 | Accept pipeline input: False 99 | Accept wildcard characters: False 100 | ``` 101 | 102 | ### -Closed 103 | sets the alert to closed 104 | 105 | ```yaml 106 | Type: SwitchParameter 107 | Parameter Sets: (All) 108 | Aliases: 109 | 110 | Required: False 111 | Position: Named 112 | Default value: False 113 | Accept pipeline input: False 114 | Accept wildcard characters: False 115 | ``` 116 | 117 | ### -Open 118 | sets the alert to open 119 | 120 | ```yaml 121 | Type: SwitchParameter 122 | Parameter Sets: (All) 123 | Aliases: 124 | 125 | Required: False 126 | Position: Named 127 | Default value: False 128 | Accept pipeline input: False 129 | Accept wildcard characters: False 130 | ``` 131 | 132 | ### -closedDateTime 133 | Sets the close time 134 | 135 | ```yaml 136 | Type: DateTime 137 | Parameter Sets: (All) 138 | Aliases: 139 | 140 | Required: False 141 | Position: 4 142 | Default value: None 143 | Accept pipeline input: False 144 | Accept wildcard characters: False 145 | ``` 146 | 147 | ### -comments 148 | Sets any comments 149 | 150 | ```yaml 151 | Type: String 152 | Parameter Sets: (All) 153 | Aliases: 154 | 155 | Required: False 156 | Position: 5 157 | Default value: None 158 | Accept pipeline input: False 159 | Accept wildcard characters: False 160 | ``` 161 | 162 | ### -feedback 163 | Sets the Feedback; 0,1,2,3 164 | 165 | ```yaml 166 | Type: String 167 | Parameter Sets: (All) 168 | Aliases: 169 | 170 | Required: False 171 | Position: 6 172 | Default value: None 173 | Accept pipeline input: False 174 | Accept wildcard characters: False 175 | ``` 176 | 177 | ### -Status 178 | Sets the Feedback; 0,1,2,3 179 | 180 | ```yaml 181 | Type: String 182 | Parameter Sets: (All) 183 | Aliases: 184 | 185 | Required: False 186 | Position: 7 187 | Default value: None 188 | Accept pipeline input: False 189 | Accept wildcard characters: False 190 | ``` 191 | 192 | ### -Tags 193 | Sets any tags 194 | 195 | ```yaml 196 | Type: String 197 | Parameter Sets: (All) 198 | Aliases: 199 | 200 | Required: False 201 | Position: 8 202 | Default value: None 203 | Accept pipeline input: False 204 | Accept wildcard characters: False 205 | ``` 206 | 207 | ### CommonParameters 208 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). 209 | 210 | ## INPUTS 211 | 212 | ## OUTPUTS 213 | 214 | ## NOTES 215 | 216 | ## RELATED LINKS 217 | -------------------------------------------------------------------------------- /Functions/Get-GraphSecurityAuthToken.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Gets a authenticaiton token to be used by other Microsoft Graph Security module cmdlets. 4 | .DESCRIPTION 5 | Get-GraphSecurityAuthToken gets an authentication token to be used by other Microsoft Graph Security module cmdlets. 6 | 7 | When using Get-GraphSecurityAuthToken you will be prompted to provide your Azure AD username (UPN), password and AppId. 8 | 9 | Get-GraphSecurityAuthToken takes the token and stores them in a special global session variable called $GraphSecurityAuthToken. 10 | 11 | All Microsoft Graph Security Module cmdlets reference that special global variable to pass requests to your tenant. 12 | 13 | .EXAMPLE 14 | Get-GraphSecurityAuthToken 15 | 16 | This prompts the user to enter both their username as well as their password, then prompts for AppId. 17 | 18 | Username = username (Example: Nicholas@contoso.com) 19 | Password = Password (Example: Sup3rS3cureP@ssw0rd!) 20 | Username = AppId 21 | Password = AppId (Example: 64407e7c-8522-417f-a003-f69ad0b1a89b) 22 | 23 | C:\>$GraphSecurityAuthToken 24 | 25 | To verify your auth token is set in the current session, run the above command. 26 | 27 | UserName Password 28 | -------- -------- 29 | nicholas@contoso.com System.Security.SecureString 30 | 31 | .FUNCTIONALITY 32 | Get-GraphSecurityAuthToken is intended to get an authentication token into a global session variable to allow other cmdlets to authenticate when passing requests. 33 | #> 34 | 35 | function Get-GraphSecurityAuthToken { 36 | 37 | [CmdletBinding()] 38 | 39 | Param 40 | ( 41 | 42 | # Specifies the password. 43 | [Parameter(Mandatory = $false)] 44 | [ValidateNotNullOrEmpty()] 45 | [System.Management.Automation.PSCredential]$GraphSecurityCredential 46 | 47 | ) 48 | 49 | Try { $Username = Select-GraphSecurityUsername } 50 | Catch { Throw $_ } 51 | 52 | Try { $AppId = Select-GraphSecurityAppId } 53 | Catch { Throw $_ } 54 | 55 | $user = New-Object "System.Net.Mail.MailAddress" -ArgumentList $Username 56 | 57 | $tenant = $user.Host 58 | 59 | Write-Verbose "Checking for AzureAD module..." 60 | 61 | $AadModule = Get-Module -Name "AzureAD" -ListAvailable 62 | 63 | if ($null -eq $AadModule) { 64 | 65 | Write-Verbose "AzureAD PowerShell module not found, looking for AzureADPreview" 66 | 67 | $AadModule = Get-Module -Name "AzureADPreview" -ListAvailable 68 | 69 | } 70 | 71 | if ($null -eq $AadModule) { 72 | 73 | Install-GraphSecurityAADModule 74 | 75 | $AadModule = Get-Module -Name "AzureAD" -ListAvailable 76 | 77 | } 78 | 79 | # Getting path to ActiveDirectory Assemblies 80 | # If the module count is greater than 1 find the latest version 81 | 82 | if ($AadModule.count -gt 1) { 83 | 84 | $Latest_Version = ($AadModule | Select-Object version | Sort-Object)[-1] 85 | 86 | $aadModule = $AadModule | Where-Object { $_.version -eq $Latest_Version.version } 87 | 88 | # Checking if there are multiple versions of the same module found 89 | 90 | if ($AadModule.count -gt 1) { 91 | 92 | $aadModule = $AadModule | Select-Object -Unique 93 | 94 | } 95 | 96 | $adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll" 97 | 98 | $adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll" 99 | 100 | } 101 | 102 | else { 103 | 104 | $adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll" 105 | 106 | $adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll" 107 | 108 | } 109 | 110 | [System.Reflection.Assembly]::LoadFrom($adal) | Out-Null 111 | 112 | [System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null 113 | 114 | $redirectUri = "urn:ietf:wg:oauth:2.0:oob" 115 | 116 | $resourceAppIdURI = "https://graph.microsoft.com" 117 | 118 | $authority = "https://login.microsoftonline.com/$Tenant" 119 | 120 | try { 121 | 122 | $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority 123 | 124 | # https://msdn.microsoft.com/en-us/library/azure/microsoft.identitymodel.clients.activedirectory.promptbehavior.aspx 125 | # Change the prompt behaviour to force credentials each time: Auto, Always, Never, RefreshSession 126 | 127 | $platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto" 128 | 129 | $userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($Username, "OptionalDisplayableId") 130 | 131 | $authResult = $authContext.AcquireTokenAsync($resourceAppIdURI, $AppId, $redirectUri, $platformParameters, $userId).Result 132 | 133 | if ($authResult.AccessToken) { 134 | 135 | # Creating header for Authorization token 136 | 137 | $global:GraphSecurityAuthHeader = @{ 138 | 'Content-Type' = 'application/json' 139 | 'Authorization' = "Bearer " + $authResult.AccessToken 140 | 'ExpiresOn' = $authResult.ExpiresOn 141 | 'Prefer' = 'return=representation' 142 | } 143 | 144 | } 145 | 146 | else { 147 | 148 | 149 | Write-Warning "Authorization Access Token is null, please re-run authentication..." 150 | 151 | break 152 | 153 | } 154 | 155 | } 156 | 157 | catch { 158 | 159 | Write-Verbose $_.Exception.Message 160 | Write-Verbose $_.Exception.ItemName 161 | 162 | break 163 | 164 | } 165 | 166 | } -------------------------------------------------------------------------------- /Functions/Set-GraphSecurityAlert.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Sets the status of alerts in Microsoft Graph Security. 4 | 5 | .DESCRIPTION 6 | Sets the status of alerts in Microsoft Graph Security. 7 | 8 | There are multiple parameter: 9 | 10 | assignedTo: Used for setting the name of the analyst the alert is assigned to for triage, investigation, or remediation. 11 | closed: Used to close the alert [default is no] 12 | closedDateTime: Time at which the alert was closed. [default is current date and time] 13 | comments: Analyst comments on the alert. 14 | feedback: Analyst feedback on the alert. Possible values are: unknown, truePositive, falsePositive, benignPositive. 15 | status: Alert lifecycle status (stage). Possible values are: unknown, newAlert, inProgress, resolved. 16 | tags: User-definable labels that can be applied to an alert and can serve as filter conditions. 17 | 18 | An alert id is always required to be specified either explicity or implicitly from the pipeline. 19 | 20 | .EXAMPLE 21 | Set-GraphSecurityAlert -id D0ED0BD3-AB24-3E05-A4D3-171280CA3CB9 -Status resolved -Feedback truePositive 22 | 23 | This marks a single specified alert as 'resolved' and as a 'truePositive'. 24 | 25 | .EXAMPLE 26 | Get-GraphSecurityAlert -id D0ED0BD3-AB24-3E05-A4D3-171280CA3CB9 | Set-GraphSecurityAlert -Status inProgress -Assignedto joe@contoso.com 27 | 28 | This will set the status of the specified alert as "inProgress" and who is working it "joe@contoso.com". 29 | 30 | .FUNCTIONALITY 31 | Set-GraphSecurityAlert is intended to function as a mechanism for setting the status of alerts using Microsoft Graph Security. 32 | #> 33 | 34 | function Set-GraphSecurityAlert { 35 | 36 | [CmdletBinding()] 37 | 38 | Param 39 | ( 40 | 41 | # Specifies the alert id 42 | [Parameter(Mandatory = $false, ValueFromPipeline = $true)] 43 | [string]$id, 44 | 45 | #Specifies the API Version 46 | [Parameter(Mandatory = $false)] 47 | [ValidateSet("v1", "Beta")] 48 | [string]$Version = "v1", 49 | 50 | #Sets the owner of the alert 51 | [Parameter(Mandatory = $false)] 52 | [ValidatePattern("[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*")] 53 | [string]$assignedTo, 54 | 55 | #sets the alert to closed 56 | [Parameter(Mandatory = $false)] 57 | [switch]$Closed, 58 | 59 | #sets the alert to open 60 | [Parameter(Mandatory = $false)] 61 | [switch]$Open, 62 | 63 | #Sets the close time 64 | [Parameter(Mandatory = $false)] 65 | [datetime]$closedDateTime, 66 | 67 | #Sets any comments 68 | [Parameter(Mandatory = $false)] 69 | [string]$comments, 70 | 71 | #Sets the Feedback; 0,1,2,3 72 | [Parameter(Mandatory = $false)] 73 | [ValidateSet("unknown", "truePositive", "falsePositive", "benignPositive")] 74 | [string]$feedback, 75 | 76 | #Sets the Feedback; 0,1,2,3 77 | [Parameter(Mandatory = $false)] 78 | [ValidateSet("unknown", "newAlert", "inProgress", "resolved")] 79 | [string]$Status, 80 | 81 | #Sets any tags 82 | [Parameter(Mandatory = $false)] 83 | [string]$Tags 84 | 85 | ) 86 | 87 | Begin { 88 | 89 | Try {Test-GraphSecurityAuthToken } 90 | Catch { Throw $_ } 91 | 92 | If ($Closed -and $Open) { 93 | Write-Error "You cannot specify open and close parameters at the same time" 94 | exit 95 | } 96 | 97 | } 98 | 99 | Process { 100 | $Resource = "security/alerts/$id" 101 | 102 | if ($Version -eq "Beta") { 103 | 104 | $uri = "https://graph.microsoft.com/beta/$($resource)" 105 | 106 | } 107 | 108 | Else { 109 | 110 | $uri = "https://graph.microsoft.com/$Version.0/$($resource)" 111 | 112 | } 113 | 114 | $alert = Invoke-RestMethod -Uri $uri -Headers $GraphSecurityAuthHeader -Method Get 115 | 116 | $provider = $Alert.vendorInformation.provider 117 | 118 | $Vendor = $Alert.vendorInformation.vendor 119 | 120 | #need to build the body https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/alert_update 121 | $baseBody = @" 122 | { 123 | "vendorInformation": { 124 | "provider": "$provider", 125 | "vendor": "$Vendor" 126 | } 127 | } 128 | "@ 129 | $objBody = ConvertFrom-Json $baseBody 130 | 131 | if ($assignedTo) { $objBody | Add-Member -Type NoteProperty -Name 'assignedTo' -Value "$assignedTo" } 132 | 133 | if ($Closed) { 134 | 135 | $DateTime = (Get-Date -UFormat '+%Y-%m-%dT%H:%M:%SZ') 136 | 137 | $objBody | Add-Member -Type NoteProperty -Name 'closedDateTime' -Value "$DateTime" 138 | 139 | } 140 | 141 | if ($closedDateTime) { 142 | 143 | $closedDateTime = (Get-Date -Date $closedDateTime -UFormat '+%Y-%m-%dT%H:%M:%SZ') 144 | 145 | $objBody | Add-Member -Type NoteProperty -Name 'closedDateTime' -Value "$closedDateTime" 146 | 147 | } 148 | 149 | if ($Open) { $objBody | Add-Member -Type NoteProperty -Name 'closedDateTime' -Value $null } 150 | 151 | if ($comments) { $objBody | Add-Member -Type NoteProperty -Name 'comments' -Value @("$comments") } 152 | 153 | if ($feedback) { $objBody | Add-Member -Type NoteProperty -Name 'feedback' -Value "$feedback" } 154 | 155 | if ($status) { $objBody | Add-Member -Type NoteProperty -Name 'status' -Value "$status" } 156 | 157 | if ($tags) { $objBody | Add-Member -Type NoteProperty -Name 'tags' -Value @("$tags") } 158 | 159 | $Body = ConvertTo-Json $objBody -Depth 5 160 | 161 | try { 162 | 163 | Invoke-RestMethod -Uri $uri -Headers $GraphSecurityAuthHeader -Method Patch -Body $Body 164 | 165 | } 166 | 167 | catch { 168 | 169 | $ex = $_.Exception 170 | 171 | $errorResponse = $ex.Response.GetResponseStream() 172 | 173 | $reader = New-Object System.IO.StreamReader($errorResponse) 174 | 175 | $reader.BaseStream.Position = 0 176 | 177 | $reader.DiscardBufferedData() 178 | 179 | $responseBody = $reader.ReadToEnd(); 180 | 181 | Write-Verbose "Response content:`n$responseBody" 182 | 183 | Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)" 184 | 185 | 186 | 187 | break 188 | 189 | } 190 | 191 | } 192 | 193 | End { 194 | 195 | #Do Nothing 196 | } 197 | 198 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | -------------------------------------------------------------------------------- /Docs/Get-GraphSecurityAlert.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: MicrosoftGraphSecurity-help.xml 3 | Module Name: MicrosoftGraphSecurity 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-GraphSecurityAlert 9 | 10 | ## SYNOPSIS 11 | Gets alerts in Microsoft Graph Security. 12 | 13 | ## SYNTAX 14 | 15 | ### Default (Default) 16 | ``` 17 | Get-GraphSecurityAlert [-Version ] [] 18 | ``` 19 | 20 | ### List 21 | ``` 22 | Get-GraphSecurityAlert [-Version ] [-top ] [-skip ] [-orderBy ] 23 | [-riskScore ] [-activityGroupName ] [-assignedTo ] [-azureSubscriptionId ] 24 | [-azureTenantId ] [-category ] [-comments ] [-confidence ] 25 | [-detectionIds ] [-feedback ] [-severity ] [-sourceMaterials ] 26 | [-status ] [-tags ] [-title ] [-provider ] [-vendor ] 27 | [-aadUserId ] [-accountName ] [-emailRole ] [-userPrincipalName ] 28 | [-eventDateTimeAfter ] [-eventDateTimeBefore ] [-createdDateTimeAfter ] 29 | [-createdDateTimeBefore ] [-closedDateTimeAfter ] [-closedDateTimeBefore ] 30 | [-lastModifiedDateTimeAfter ] [-lastModifiedDateTimeBefore ] [] 31 | ``` 32 | 33 | ### Fetch 34 | ``` 35 | Get-GraphSecurityAlert [-Version ] [-Identity] [] 36 | ``` 37 | 38 | ### Count 39 | ``` 40 | Get-GraphSecurityAlert [-count ] [] 41 | ``` 42 | 43 | ## DESCRIPTION 44 | Gets alerts in Microsoft Graph Security. 45 | 46 | Without parameters, Get-GraphSecurityAlert gets 100 alerts and associated properties. 47 | 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. 48 | 49 | There are multiple parameter sets: 50 | 51 | ## EXAMPLES 52 | 53 | ### EXAMPLE 1 54 | ``` 55 | Get-GraphSecurityAlert 56 | ``` 57 | 58 | This will default grab the Top 100 alerts. 59 | 60 | ### EXAMPLE 2 61 | ``` 62 | Get-GraphSecurityAlert -id D0ED9BD3-AB24-3E05-A4D3-171280CA3CB9 63 | ``` 64 | 65 | This will get a single alert. 66 | 67 | ### EXAMPLE 3 68 | ``` 69 | Get-GraphSecurityAlert -provider MCAS -severity high 70 | ``` 71 | 72 | This will get all alerts from MCAS with high severity. 73 | 74 | ## PARAMETERS 75 | 76 | ### -Version 77 | Specifies the API Version 78 | 79 | ```yaml 80 | Type: String 81 | Parameter Sets: Default, List, Fetch 82 | Aliases: 83 | 84 | Required: False 85 | Position: Named 86 | Default value: V1.0 87 | Accept pipeline input: False 88 | Accept wildcard characters: False 89 | ``` 90 | 91 | ### -Identity 92 | Fetches an activity object by its unique identifier. 93 | 94 | ```yaml 95 | Type: String 96 | Parameter Sets: Fetch 97 | Aliases: 98 | 99 | Required: True 100 | Position: 1 101 | Default value: None 102 | Accept pipeline input: True (ByPropertyName, ByValue) 103 | Accept wildcard characters: False 104 | ``` 105 | 106 | ### -top 107 | Specifies the maximum number of results to retrieve 108 | 109 | ```yaml 110 | Type: Int32 111 | Parameter Sets: List 112 | Aliases: 113 | 114 | Required: False 115 | Position: Named 116 | Default value: 100 117 | Accept pipeline input: False 118 | Accept wildcard characters: False 119 | ``` 120 | 121 | ### -skip 122 | Specifies the number of records, from the beginning of the result set, to skip. 123 | 124 | ```yaml 125 | Type: Int32 126 | Parameter Sets: List 127 | Aliases: 128 | 129 | Required: False 130 | Position: Named 131 | Default value: 0 132 | Accept pipeline input: False 133 | Accept wildcard characters: False 134 | ``` 135 | 136 | ### -count 137 | Returns the number of alerts to the user 138 | 139 | ```yaml 140 | Type: String 141 | Parameter Sets: Count 142 | Aliases: 143 | 144 | Required: False 145 | Position: Named 146 | Default value: False 147 | Accept pipeline input: False 148 | Accept wildcard characters: False 149 | ``` 150 | 151 | ### -orderBy 152 | Currently orderBy Ascending by default 153 | 154 | ```yaml 155 | Type: String 156 | Parameter Sets: List 157 | Aliases: 158 | 159 | Required: False 160 | Position: Named 161 | Default value: None 162 | Accept pipeline input: False 163 | Accept wildcard characters: False 164 | ``` 165 | 166 | ### -riskScore 167 | Provider generated/calculated risk score of the network connection. 168 | Recommended value range of 0-1, which equates to a percentage. 169 | 170 | ```yaml 171 | Type: String 172 | Parameter Sets: List 173 | Aliases: 174 | 175 | Required: False 176 | Position: Named 177 | Default value: None 178 | Accept pipeline input: False 179 | Accept wildcard characters: False 180 | ``` 181 | 182 | ### -activityGroupName 183 | Name or alias of the activity group (attacker) this alert is attributed to. 184 | 185 | ```yaml 186 | Type: String 187 | Parameter Sets: List 188 | Aliases: 189 | 190 | Required: False 191 | Position: Named 192 | Default value: None 193 | Accept pipeline input: False 194 | Accept wildcard characters: False 195 | ``` 196 | 197 | ### -assignedTo 198 | Name of the analyst the alert is assigned to for triage, investigation, or remediation (supports update). 199 | 200 | ```yaml 201 | Type: String 202 | Parameter Sets: List 203 | Aliases: 204 | 205 | Required: False 206 | Position: Named 207 | Default value: None 208 | Accept pipeline input: False 209 | Accept wildcard characters: False 210 | ``` 211 | 212 | ### -azureSubscriptionId 213 | Azure subscription ID, present if this alert is related to an Azure resource. 214 | 215 | ```yaml 216 | Type: String 217 | Parameter Sets: List 218 | Aliases: 219 | 220 | Required: False 221 | Position: Named 222 | Default value: None 223 | Accept pipeline input: False 224 | Accept wildcard characters: False 225 | ``` 226 | 227 | ### -azureTenantId 228 | Azure Active Directory tenant ID. 229 | Required. 230 | 231 | ```yaml 232 | Type: String 233 | Parameter Sets: List 234 | Aliases: 235 | 236 | Required: False 237 | Position: Named 238 | Default value: None 239 | Accept pipeline input: False 240 | Accept wildcard characters: False 241 | ``` 242 | 243 | ### -category 244 | Category of the alert (for example, credentialTheft, ransomware, etc.). 245 | 246 | ```yaml 247 | Type: String 248 | Parameter Sets: List 249 | Aliases: 250 | 251 | Required: False 252 | Position: Named 253 | Default value: None 254 | Accept pipeline input: False 255 | Accept wildcard characters: False 256 | ``` 257 | 258 | ### -comments 259 | Customer-provided comments on alert (for customer alert management) (supports update). 260 | 261 | ```yaml 262 | Type: String[] 263 | Parameter Sets: List 264 | Aliases: 265 | 266 | Required: False 267 | Position: Named 268 | Default value: None 269 | Accept pipeline input: False 270 | Accept wildcard characters: False 271 | ``` 272 | 273 | ### -confidence 274 | Confidence of the detection logic (percentage between 1-100). 275 | 276 | ```yaml 277 | Type: String[] 278 | Parameter Sets: List 279 | Aliases: 280 | 281 | Required: False 282 | Position: Named 283 | Default value: None 284 | Accept pipeline input: False 285 | Accept wildcard characters: False 286 | ``` 287 | 288 | ### -detectionIds 289 | Set of alerts related to this alert entity (each alert is pushed to the SIEM as a separate record). 290 | 291 | ```yaml 292 | Type: String[] 293 | Parameter Sets: List 294 | Aliases: 295 | 296 | Required: False 297 | Position: Named 298 | Default value: None 299 | Accept pipeline input: False 300 | Accept wildcard characters: False 301 | ``` 302 | 303 | ### -feedback 304 | Analyst feedback on the alert. 305 | 306 | ```yaml 307 | Type: String 308 | Parameter Sets: List 309 | Aliases: 310 | 311 | Required: False 312 | Position: Named 313 | Default value: None 314 | Accept pipeline input: False 315 | Accept wildcard characters: False 316 | ``` 317 | 318 | ### -severity 319 | Alert severity - set by vendor/provider. 320 | 321 | ```yaml 322 | Type: String 323 | Parameter Sets: List 324 | Aliases: 325 | 326 | Required: False 327 | Position: Named 328 | Default value: None 329 | Accept pipeline input: False 330 | Accept wildcard characters: False 331 | ``` 332 | 333 | ### -sourceMaterials 334 | Hyperlinks (URIs) to the source material related to the alert, for example, provider's user interface for alerts or log search, etc. 335 | 336 | ```yaml 337 | Type: String[] 338 | Parameter Sets: List 339 | Aliases: 340 | 341 | Required: False 342 | Position: Named 343 | Default value: None 344 | Accept pipeline input: False 345 | Accept wildcard characters: False 346 | ``` 347 | 348 | ### -status 349 | Alert lifecycle status (stage). 350 | 351 | ```yaml 352 | Type: String 353 | Parameter Sets: List 354 | Aliases: 355 | 356 | Required: False 357 | Position: Named 358 | Default value: None 359 | Accept pipeline input: False 360 | Accept wildcard characters: False 361 | ``` 362 | 363 | ### -tags 364 | User-definable labels that can be applied to an alert and can serve as filter conditions (for example "HVA", "SAW", etc.) (supports update). 365 | 366 | ```yaml 367 | Type: String[] 368 | Parameter Sets: List 369 | Aliases: 370 | 371 | Required: False 372 | Position: Named 373 | Default value: None 374 | Accept pipeline input: False 375 | Accept wildcard characters: False 376 | ``` 377 | 378 | ### -title 379 | Alert title. 380 | Required. 381 | 382 | ```yaml 383 | Type: String 384 | Parameter Sets: List 385 | Aliases: 386 | 387 | Required: False 388 | Position: Named 389 | Default value: None 390 | Accept pipeline input: False 391 | Accept wildcard characters: False 392 | ``` 393 | 394 | ### -provider 395 | Specific provider (product/service - not vendor company); for example, WindowsDefenderATP. 396 | 397 | ```yaml 398 | Type: String 399 | Parameter Sets: List 400 | Aliases: 401 | 402 | Required: False 403 | Position: Named 404 | Default value: None 405 | Accept pipeline input: False 406 | Accept wildcard characters: False 407 | ``` 408 | 409 | ### -vendor 410 | Name of the alert vendor (for example, Microsoft, Dell, FireEye). 411 | Required 412 | 413 | ```yaml 414 | Type: String 415 | Parameter Sets: List 416 | Aliases: 417 | 418 | Required: False 419 | Position: Named 420 | Default value: None 421 | Accept pipeline input: False 422 | Accept wildcard characters: False 423 | ``` 424 | 425 | ### -aadUserId 426 | AAD User object identifier (GUID) - represents the physical/multi-account user entity. 427 | 428 | ```yaml 429 | Type: String 430 | Parameter Sets: List 431 | Aliases: 432 | 433 | Required: False 434 | Position: Named 435 | Default value: None 436 | Accept pipeline input: False 437 | Accept wildcard characters: False 438 | ``` 439 | 440 | ### -accountName 441 | Account name of user account (without Active Directory domain or DNS domain) - (also called mailNickName). 442 | Case-Sensitive 443 | 444 | ```yaml 445 | Type: String 446 | Parameter Sets: List 447 | Aliases: 448 | 449 | Required: False 450 | Position: Named 451 | Default value: None 452 | Accept pipeline input: False 453 | Accept wildcard characters: False 454 | ``` 455 | 456 | ### -emailRole 457 | For email-related alerts - user account's email 'role'. 458 | 459 | ```yaml 460 | Type: String 461 | Parameter Sets: List 462 | Aliases: 463 | 464 | Required: False 465 | Position: Named 466 | Default value: None 467 | Accept pipeline input: False 468 | Accept wildcard characters: False 469 | ``` 470 | 471 | ### -userPrincipalName 472 | User sign-in name - internet format: (user account name)@(user account DNS domain name). 473 | 474 | ```yaml 475 | Type: String 476 | Parameter Sets: List 477 | Aliases: 478 | 479 | Required: False 480 | Position: Named 481 | Default value: None 482 | Accept pipeline input: False 483 | Accept wildcard characters: False 484 | ``` 485 | 486 | ### -eventDateTimeAfter 487 | Date Time Params ###### 488 | 489 | ```yaml 490 | Type: String 491 | Parameter Sets: List 492 | Aliases: 493 | 494 | Required: False 495 | Position: Named 496 | Default value: None 497 | Accept pipeline input: False 498 | Accept wildcard characters: False 499 | ``` 500 | 501 | ### -eventDateTimeBefore 502 | {{ Fill eventDateTimeBefore Description }} 503 | 504 | ```yaml 505 | Type: String 506 | Parameter Sets: List 507 | Aliases: 508 | 509 | Required: False 510 | Position: Named 511 | Default value: None 512 | Accept pipeline input: False 513 | Accept wildcard characters: False 514 | ``` 515 | 516 | ### -createdDateTimeAfter 517 | {{ Fill createdDateTimeAfter Description }} 518 | 519 | ```yaml 520 | Type: String 521 | Parameter Sets: List 522 | Aliases: 523 | 524 | Required: False 525 | Position: Named 526 | Default value: None 527 | Accept pipeline input: False 528 | Accept wildcard characters: False 529 | ``` 530 | 531 | ### -createdDateTimeBefore 532 | {{ Fill createdDateTimeBefore Description }} 533 | 534 | ```yaml 535 | Type: String 536 | Parameter Sets: List 537 | Aliases: 538 | 539 | Required: False 540 | Position: Named 541 | Default value: None 542 | Accept pipeline input: False 543 | Accept wildcard characters: False 544 | ``` 545 | 546 | ### -closedDateTimeAfter 547 | {{ Fill closedDateTimeAfter Description }} 548 | 549 | ```yaml 550 | Type: String 551 | Parameter Sets: List 552 | Aliases: 553 | 554 | Required: False 555 | Position: Named 556 | Default value: None 557 | Accept pipeline input: False 558 | Accept wildcard characters: False 559 | ``` 560 | 561 | ### -closedDateTimeBefore 562 | {{ Fill closedDateTimeBefore Description }} 563 | 564 | ```yaml 565 | Type: String 566 | Parameter Sets: List 567 | Aliases: 568 | 569 | Required: False 570 | Position: Named 571 | Default value: None 572 | Accept pipeline input: False 573 | Accept wildcard characters: False 574 | ``` 575 | 576 | ### -lastModifiedDateTimeAfter 577 | {{ Fill lastModifiedDateTimeAfter Description }} 578 | 579 | ```yaml 580 | Type: String 581 | Parameter Sets: List 582 | Aliases: 583 | 584 | Required: False 585 | Position: Named 586 | Default value: None 587 | Accept pipeline input: False 588 | Accept wildcard characters: False 589 | ``` 590 | 591 | ### -lastModifiedDateTimeBefore 592 | {{ Fill lastModifiedDateTimeBefore Description }} 593 | 594 | ```yaml 595 | Type: String 596 | Parameter Sets: List 597 | Aliases: 598 | 599 | Required: False 600 | Position: Named 601 | Default value: None 602 | Accept pipeline input: False 603 | Accept wildcard characters: False 604 | ``` 605 | 606 | ### CommonParameters 607 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). 608 | 609 | ## INPUTS 610 | 611 | ## OUTPUTS 612 | 613 | ## NOTES 614 | 615 | ## RELATED LINKS 616 | -------------------------------------------------------------------------------- /Functions/Get-GraphSecurityAlert.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .Synopsis 3 | Gets alerts in Microsoft Graph Security. 4 | 5 | .DESCRIPTION 6 | Gets alerts in Microsoft Graph Security. 7 | 8 | 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. 9 | 10 | There are multiple parameter sets: 11 | 12 | .EXAMPLE 13 | Get-GraphSecurityAlert 14 | 15 | This will default grab the Top 100 alerts. 16 | 17 | .EXAMPLE 18 | Get-GraphSecurityAlert -id D0ED9BD3-AB24-3E05-A4D3-171280CA3CB9 19 | 20 | This will get a single alert. 21 | 22 | .EXAMPLE 23 | Get-GraphSecurityAlert -provider MCAS -severity high 24 | 25 | This will get all alerts from MCAS with high severity. 26 | 27 | .FUNCTIONALITY 28 | Get-GraphSecurityAlert is intended to function as a mechanism for getting alerts using Microsoft Graph Security. 29 | #> 30 | function Get-GraphSecurityAlert { 31 | [cmdletbinding(DefaultParameterSetName = 'Default')] 32 | param 33 | ( 34 | #Specifies the API Version 35 | [Parameter(ParameterSetName = 'Default', Mandatory = $false)] 36 | [Parameter(ParameterSetName = 'Fetch', Mandatory = $false)] 37 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 38 | [ValidateSet("v1.0", "Beta")] 39 | [string]$Version = "v1.0", 40 | 41 | # Fetches an activity object by its unique identifier. 42 | [Parameter(ParameterSetName = 'Fetch', Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] 43 | [ValidateNotNullOrEmpty()] 44 | [string]$id, 45 | 46 | # Specifies the maximum number of results to retrieve 47 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 48 | [ValidateRange(1, 1000)] 49 | [int]$top = "100", 50 | 51 | # Specifies the number of records, from the beginning of the result set, to skip. 52 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 53 | [ValidateRange(0, 5000)] 54 | [int]$skip = 0, 55 | 56 | # Returns the number of alerts to the user 57 | [Parameter(ParameterSetName = 'Count', Mandatory = $false)] 58 | [ValidateSet("true", "false")] 59 | [string]$count = "false", 60 | 61 | ##### OrderBy Param ##### 62 | 63 | #Currently orderBy Ascending by default 64 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 65 | [ValidateSet("riskScore", "tags", "id", 66 | "azureTenantId", "activityGroupName", "assignedTo", 67 | "category", "closedDateTime", "comments", 68 | "confidence", "createdDateTime", "description", 69 | "detectionIds", "eventDateTime", "feedback", 70 | "lastModifiedDateTime", "recommendedActions", "severity", 71 | "sourceMaterials", "status", "title", 72 | "vendorInformation", "cloudAppStates", "fileStates", 73 | "hostStates", "malwareStates", "networkConnections", 74 | "processes", "registryKeyStates", "triggers", 75 | "userStates", "vulnerabilityStates")] 76 | [string]$orderBy = "none", 77 | 78 | #### OData Query Params ##### 79 | 80 | # Provider generated/calculated risk score of the network connection. Recommended value range of 0-1, which equates to a percentage. 81 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 82 | [ValidateNotNullOrEmpty()] 83 | [string]$riskScore, 84 | 85 | # Name or alias of the activity group (attacker) this alert is attributed to. 86 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 87 | [ValidateNotNullOrEmpty()] 88 | [string]$activityGroupName, 89 | 90 | # Name of the analyst the alert is assigned to for triage, investigation, or remediation (supports update). 91 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 92 | [ValidateNotNullOrEmpty()] 93 | [string]$assignedTo, 94 | 95 | # Azure subscription ID, present if this alert is related to an Azure resource. 96 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 97 | [ValidateNotNullOrEmpty()] 98 | [string]$azureSubscriptionId, 99 | 100 | # Azure Active Directory tenant ID. Required. 101 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 102 | [ValidateNotNullOrEmpty()] 103 | [string]$azureTenantId, 104 | 105 | # Category of the alert (for example, credentialTheft, ransomware, etc.). 106 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 107 | [ValidateNotNullOrEmpty()] 108 | [string]$category, 109 | 110 | # Customer-provided comments on alert (for customer alert management) (supports update). 111 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 112 | [ValidateNotNullOrEmpty()] 113 | [string[]]$comments, 114 | 115 | # Confidence of the detection logic (percentage between 1-100). 116 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 117 | [ValidateNotNullOrEmpty()] 118 | [string[]]$confidence, 119 | 120 | # Set of alerts related to this alert entity (each alert is pushed to the SIEM as a separate record). 121 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 122 | [ValidateNotNullOrEmpty()] 123 | [string[]]$detectionIds, 124 | 125 | # Analyst feedback on the alert. 126 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 127 | [ValidateNotNullOrEmpty()] 128 | [ValidateSet("unknown", "truePositive", "falsePositive", "begninPostive")] 129 | [string]$feedback = "none", 130 | 131 | # Alert severity - set by vendor/provider. 132 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 133 | [ValidateNotNullOrEmpty()] 134 | [ValidateSet("unknown", "informational", "low", "medium", "high")] 135 | [string]$severity = "none", 136 | 137 | # Hyperlinks (URIs) to the source material related to the alert, for example, provider's user interface for alerts or log search, etc. 138 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 139 | [ValidateNotNullOrEmpty()] 140 | [string[]]$sourceMaterials, 141 | 142 | # Alert lifecycle status (stage). 143 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 144 | [ValidateNotNullOrEmpty()] 145 | [ValidateSet("unknown", "newAlert", "inProgress", "resolved")] 146 | [string]$status = "none", 147 | 148 | # User-definable labels that can be applied to an alert and can serve as filter conditions (for example "HVA", "SAW", etc.) (supports update). 149 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 150 | [ValidateNotNullOrEmpty()] 151 | [string[]]$tags, 152 | 153 | # Alert title. Required. 154 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 155 | [ValidateNotNullOrEmpty()] 156 | [ValidateScript( { $_.Length -ge 5 })] 157 | [string]$title, 158 | 159 | ####### Vendor Information ###### 160 | 161 | # Specific provider (product/service - not vendor company); for example, WindowsDefenderATP. 162 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 163 | [ValidateNotNullOrEmpty()] 164 | [string]$provider, 165 | 166 | # Name of the alert vendor (for example, Microsoft, Dell, FireEye). Required 167 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 168 | [ValidateNotNullOrEmpty()] 169 | [string]$vendor, 170 | 171 | ####### User State Information ###### 172 | 173 | # AAD User object identifier (GUID) - represents the physical/multi-account user entity. 174 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 175 | [ValidateNotNullOrEmpty()] 176 | [string]$aadUserId, 177 | 178 | # Account name of user account (without Active Directory domain or DNS domain) - (also called mailNickName). Case-Sensitive 179 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 180 | [ValidateNotNullOrEmpty()] 181 | [string]$accountName, 182 | 183 | # For email-related alerts - user account's email 'role'. 184 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 185 | [ValidateNotNullOrEmpty()] 186 | [string]$emailRole, 187 | 188 | # User sign-in name - internet format: (user account name)@(user account DNS domain name). 189 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 190 | [ValidateNotNullOrEmpty()] 191 | [string]$userPrincipalName, 192 | 193 | ####### Host Security State Information ###### 194 | 195 | <# Needs further testing, omitted for release 1.0 196 | 197 | # # Host FQDN (Fully Qualified Domain Name) (for example, machine.company.com). 198 | # [Parameter(ParameterSetName='List', Mandatory=$false)] 199 | # [ValidateNotNullOrEmpty()] 200 | # [string]$FQDN, 201 | 202 | #> 203 | 204 | <# Needs further testing, omitted for release 1.0 205 | 206 | # # Private (not routable) IPv4 or IPv6 address (see RFC 1918) at the time of the alert. 207 | # [Parameter(ParameterSetName='List', Mandatory=$false)] 208 | # [ValidateNotNullOrEmpty()] 209 | # [string]$privateIpAddress, 210 | 211 | #> 212 | 213 | <# Needs further testing, omitted for release 1.0 214 | 215 | # # Publicly routable IPv4 or IPv6 address (see RFC 1918) at time of the alert. 216 | # [Parameter(ParameterSetName='List', Mandatory=$false)] 217 | # [ValidateNotNullOrEmpty()] 218 | # [string]$publicIpAddress, 219 | 220 | #> 221 | 222 | # ####### File Security State Information ###### 223 | 224 | <# Needs further testing, omitted for release 1.0 225 | 226 | # # File name (without path). 227 | # [Parameter(ParameterSetName='List', Mandatory=$false)] 228 | # [ValidateNotNullOrEmpty()] 229 | # [string]$fileName, 230 | 231 | #> 232 | 233 | ####### Date Time Params ###### 234 | 235 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 236 | [ValidateNotNullOrEmpty()] 237 | [string]$eventDateTimeAfter = "", 238 | 239 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 240 | [ValidateNotNullOrEmpty()] 241 | [string]$eventDateTimeBefore = "", 242 | 243 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 244 | [ValidateNotNullOrEmpty()] 245 | [string]$createdDateTimeAfter = "", 246 | 247 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 248 | [ValidateNotNullOrEmpty()] 249 | [string]$createdDateTimeBefore = "", 250 | 251 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 252 | [ValidateNotNullOrEmpty()] 253 | [string]$closedDateTimeAfter = "", 254 | 255 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 256 | [ValidateNotNullOrEmpty()] 257 | [string]$closedDateTimeBefore = "", 258 | 259 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 260 | [ValidateNotNullOrEmpty()] 261 | [string]$lastModifiedDateTimeAfter = "", 262 | 263 | [Parameter(ParameterSetName = 'List', Mandatory = $false)] 264 | [ValidateNotNullOrEmpty()] 265 | [string]$lastModifiedDateTimeBefore = "" 266 | ) 267 | 268 | Begin { 269 | Try { Test-GraphSecurityAuthToken } 270 | Catch { Throw $_ } 271 | } 272 | Process { 273 | # Fetch mode should happen once for each item from the pipeline, so it goes in the 'Process' block 274 | if ($PSCmdlet.ParameterSetName -eq 'Fetch') { 275 | try { 276 | # Fetch the item by its id 277 | $resource = "security/alerts/$id" 278 | $uri = "https://graph.microsoft.com/$Version/$($resource)" 279 | $response = Invoke-RestMethod -Uri $uri -Headers $GraphSecurityAuthHeader -Method Get 280 | Write-Verbose "Calling: $uri" 281 | } 282 | catch { 283 | $ex = $_.Exception 284 | $errorResponse = $ex.Response.GetResponseStream() 285 | $reader = New-Object System.IO.StreamReader($errorResponse) 286 | $reader.BaseStream.Position = 0 287 | $reader.DiscardBufferedData() 288 | $responseBody = $reader.ReadToEnd(); 289 | Write-Verbose "Response content:`n$responseBody" 290 | Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)" 291 | 292 | break 293 | } 294 | $response 295 | } 296 | } 297 | End { 298 | 299 | # After all things have been processed in pipeline 300 | if ($PSCmdlet.ParameterSetName -eq 'List' -or $PSCmdlet.ParameterSetName -eq 'Default' -and $PSCmdlet.ParameterSetName -ne 'Fetch') { 301 | 302 | # List mode logic only needs to happen once, so it goes in the 'End' block for efficiency 303 | 304 | $body = "?`$top=$top&`$filter=" 305 | 306 | # Simple filters 307 | 308 | if ($category) { $body += "`category+eq+`'$category`' and " } 309 | if ($severity -ne "none") { $body += "severity+eq+`'$severity`' and " } 310 | if ($status -ne "none") { $body += "status+eq+`'$status`' and " } 311 | if ($title) { $body += "title+eq+`'$title`' and " } 312 | if ($azureTenantId) { $body += "azureTenantId+eq+`'$azureTenantId`' and " } 313 | if ($riskScore) { $body += "riskScore+eq+`'$riskScore`' and " } 314 | if ($tags) { $body += "tags+eq+`'$tags`' and " } 315 | if ($azureSubscriptionId) { $body += "azureSubscriptionId+eq+`'$azureSubscriptionId`' and " } 316 | if ($activityGroupName) { $body += "activityGroupName+eq+`'$activityGroupName`' and " } 317 | if ($assignedTo) { $body += "assignedTo+eq+`'$assignedTo`' and " } 318 | if ($confidence) { $body += "confidence+eq+`'$confidence`' and " } 319 | if ($detectionIds) { $body += "detectionIds+eq+`'$detectionIds`' and " } 320 | if ($sourceMaterials) { $body += "sourceMaterials+eq+`'$sourceMaterials`' and " } 321 | 322 | ####### User State Information ###### 323 | 324 | if ($aadUserId) { $body += "userStates/any(d:d/aadUserId+eq+`'$aadUserId`') and " } 325 | if ($accountName) { $body += "userStates/any(d:d/accountName+eq+`'$accountName`') and " } 326 | if ($userPrincipalName) { $body += "userStates/any(d:d/userPrincipalName+eq+`'$userPrincipalName`') and " } 327 | if ($domainName) { $body += "userStates/any(d:d/domainName+eq+`'$domainName`') and " } 328 | 329 | 330 | <# Needs further testing, omitted for release 1.0 331 | 332 | # if ($FQDN){$body += "hostSecurityState/FQDN+eq+`'$FQDN`'&"} 333 | 334 | #> 335 | <# Needs further testing, omitted for release 1.0 336 | 337 | # if ($privateIpAddress){$body += "hostSecurityState/privateIpAddress+eq+`'$privateIpAddress`'&"} 338 | 339 | #> 340 | <# Needs further testing, omitted for release 1.0 341 | 342 | # if ($publicIpAddress){$body += "hostSecurityState/publicIpAddress+eq+`'$publicIpAddress`'&"} 343 | 344 | #> 345 | 346 | ####### File Security State Information ###### 347 | <# Needs further testing, omitted for release 1.0 348 | 349 | # if ($filName){$body += "fileSecurityState/name+eq+`'$fileName`'&"} 350 | 351 | #> 352 | 353 | if ($eventDateTimeAfter) { 354 | $eventDateTimeAfter = (Get-Date -Date $eventDateTimeAfter -Format "yyyy-MM-ddTHH:mm:ssZ") 355 | $body += "eventDateTime+gt+$eventDateTimeAfter and " 356 | } 357 | 358 | if ($eventDateTimeBefore) { 359 | $eventDateTimeBefore = (Get-Date -Date $eventDateTimeBefore -Format "yyyy-MM-ddTHH:mm:ssZ") 360 | $body += "eventDateTime+lt+$eventDateTimeBefore and " 361 | } 362 | 363 | if ($createdDateTimeAfter) { 364 | $createdDateTimeAfter = (Get-Date -Date $createdDateTimeAfter -Format "yyyy-MM-ddTHH:mm:ssZ") 365 | $body += "createdDateTime+gt+$createdDateTimeAfter and " 366 | } 367 | 368 | if ($createdDateTimeBefore) { 369 | $createdDateTimeBefore = (Get-Date -Date $createdDateTimeBefore -Format "yyyy-MM-ddTHH:mm:ssZ") 370 | $body += "createdDateTime+lt+$createdDateTimeBefore and " 371 | } 372 | 373 | if ($closedDateTimeAfter) { 374 | $closedDateTimeAfter = (Get-Date -Date $closedDateTimeAfter -Format "yyyy-MM-ddTHH:mm:ssZ") 375 | $body += "closedDateTime+gt+$closedDateTimeAfter and " 376 | } 377 | 378 | if ($closedDateTimeBefore) { 379 | $closedDateTimeBefore = (Get-Date -Date $closedDateTimeBefore -Format "yyyy-MM-ddTHH:mm:ssZ") 380 | $body += "closedDateTime+lt+$closedDateTimeBefore and " 381 | } 382 | 383 | if ($lastModifiedDateTimeAfter) { 384 | $lastModifiedDateTimeAfter = (Get-Date -Date $lastModifiedDateTimeAfter -Format "yyyy-MM-ddTHH:mm:ssZ") 385 | $body += "lastModifiedDateTime+gt+$lastModifiedDateTimeAfter and " 386 | } 387 | 388 | if ($lastModifiedDateTimeBefore) { 389 | $lastModifiedDateTimeBefore = (Get-Date -Date $lastModifiedDateTimeBefore -Format "yyyy-MM-ddTHH:mm:ssZ") 390 | $body += "lastModifiedDateTime+lt+$lastModifiedDateTimeBefore and " 391 | } 392 | 393 | if ($provider) { $body += "vendorInformation/provider+eq+`'$provider`' and " } 394 | if ($vendor) { $body += "vendorInformation/vendor+eq+`'$vendor`' and " } 395 | 396 | $body = $body -replace ' and $', '' 397 | 398 | if ($Skip) { $body += "&`$skip=$Skip" } 399 | if ($orderBy -ne "none") { $body += "&`$orderBy=$orderBy" } 400 | 401 | Write-Verbose "URI Body: $body" 402 | 403 | #region ----------------------------API CALL---------------------------- 404 | 405 | Write-Verbose "In the List" 406 | try { 407 | Write-Verbose "Trying List" 408 | $resource = "security/alerts/" 409 | $uri = "https://graph.microsoft.com/$Version/$($resource)$body" 410 | 411 | $response = Invoke-RestMethod -Uri $uri -Headers $GraphSecurityAuthHeader -Method Get 412 | 413 | Write-Verbose "Trying List $response" 414 | } 415 | catch { 416 | $ex = $_.Exception 417 | $errorResponse = $ex.Response.GetResponseStream() 418 | $reader = New-Object System.IO.StreamReader($errorResponse) 419 | $reader.BaseStream.Position = 0 420 | $reader.DiscardBufferedData() 421 | $responseBody = $reader.ReadToEnd(); 422 | Write-Verbose "Response content:`n$responseBody" 423 | Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)" 424 | break 425 | } 426 | $response.value 427 | } 428 | 429 | } 430 | } --------------------------------------------------------------------------------