PSMDATP.psm1

function Add-MDATPDeviceTag{
    <#
    .Synopsis
    Add-MDATPDeviceTag
 
    .DESCRIPTION
    Add-MDATPDeviceTag adds the specified Tag to the MDATP device
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER Tag
    The value of the tag to be added
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
        Add-MDATPDeviceTag -DeviceName computer02 -Tag 'Testing' -verbose
 
        This command adds the tag 'testing' to the device 'computer02'
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 16.03.2020
    Purpose/Change: Initial script development
 
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param(
        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Tag to be added to the device
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [String]$Tag,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path "$PoshMTPconfigFilePath" -PathType Leaf ){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = "$ClientID"
            client_secret = "$ClientSecret"
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        # MDATP API URI
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"

        # change the devicename to lowercase
        $DeviceName = $DeviceName.ToLower()

        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
        If ($DeviceName){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }

        If($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $MDATPDeviceID = $ActionDevice.id
            if ($pscmdlet.ShouldProcess("$DeviceName", "Adding tag: $Tag")){
                Try{
                    # Tag machine
                    $AddTag = @{"Value" = "$Tag"; "Action"= "Add"} | ConvertTo-Json
                    $Taguri = "$MachineAPI/$MDATPDeviceID/tags"
                    $response  =Invoke-WebRequest -Uri $Taguri -Headers $Headers -Method Post -Body $AddTag
                    # end tag machine
                    If ($response.StatusCode -eq 200){
                        Write-Verbose "Tag: $Tag was successfully added to device $DeviceName"
                        $True
                    }
                    Else{
                        Write-Warning "Adding tag $Tag to device $DeviceName failed!"
                        Write-Error "StatusCode: $($response.StatusCode)"
                        $False
                    }
                }
                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)"
                }
            }
        }
    }
    End{
        Write-Verbose "Device: $DeviceName"
        Write-Verbose "DeviceID: $MDATPDeviceID"
        Write-Verbose "Added tag: $Tag"
        Write-Verbose "StatusCode: $($response.statuscode)"
        Write-Verbose "StatusDescription: $($response.StatusDescription)"
    }
}

function Add-MDATPIndicator{
    <#
    .Synopsis
    Add-MDATPIndicator
 
    .DESCRIPTION
    Add-MDATPIndicator Submits or Updates new Indicator entity.
 
    .PARAMETER IndicatorValue
    Identity of the Indicator entity. Required
 
    .PARAMETER IndicatorType
    Type of the indicator. Possible values are: "FileSha1", "FileSha256", "IpAddress", "DomainName" and "Url". Required
 
    .PARAMETER Action
    The action that will be taken if the indicator will be discovered in the organization. Possible values are: "Alert", "AlertAndBlock", and "Allowed". Required
 
    .PARAMETER Application
    The application associated with the indicator. Optional
 
    .PARAMETER Title
    Indicator alert title. Required
 
    .PARAMETER Description
    Description of the indicator. Required
 
    .PARAMETER expirationTime
    The expiration time of the indicator. Optional
 
    .PARAMETER Severity
    The severity of the indicator. possible values are: "Informational", "Low", "Medium" and "High". Optional
 
    .PARAMETER recommendedActions
    TI indicator alert recommended actions. Optional
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Add-MDATPIndicator -IndicatorValue "https://www.sample.com" -IndicatorType Url -Action Alert -Title "Sample URL detected" -Description "Access to the website sample.com detected" -severity High
 
    This command adds the URL indicator for https://www.sample.com
 
    .EXAMPLE
 
    Add-MDATPIndicator -IndicatorType DomainName www.somedomain.com -Action Alert -Title "somedomain domain detected" -Description "somedomain domain detected from custom indicator" -severity Informational
 
    This command ads the domain indicator for www.somedomain.com
 
    .EXAMPLE
    Add-MDATPIndicator -IndicatorValue "A4B52BBC94F10572296D3F8F4E25B39A1837D00F3036955C3761A9E7B2207A58" -IndicatorType FileSha256 -Action Alert -Title "Dummy File" -severity Informational -Description "dummy file detected"
 
    This command creates FileSha256 indicator
 
    .EXAMPLE
    Add-MDATPIndicator -IndicatorType IpAddress -IndicatorValue 138.223.70.10 -Action Alert -Title "IP Address indicator 138.223.70.10" -Description "access detected" -severity Medium
 
    This command adds an IP indicator
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 05.05.2020
    Purpose/Change: Initial script development
 
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param(

        # The value of the indicator
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [String]$IndicatorValue,

        # The type of the indicator
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [ValidateSet('DomainName','Url','FileSha256','IpAddress')]
        [String]$IndicatorType,

        # The Action taken
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [ValidateSet('Alert','AlertAndBlock','Block')]
        [String]$Action,

        # associated application
        [Parameter(Mandatory=$false)]
        [String]$Application,

        # Alert Title
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [String]$Title,

        # Alert Description
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [String]$Description,

        # Alert expirationTime
        [Parameter(Mandatory=$false)]
        [ValidateNotNullorEmpty()]
        [String]$expirationTime,

        # Alert Severity
        [Parameter(Mandatory=$true)]
        [ValidateSet('Informational','Low','Medium','High')]
        [String]$severity,

        # Alert recommendedActions
        [Parameter(Mandatory=$false)]
        [String]$recommendedActions,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path "$PoshMTPconfigFilePath" -PathType Leaf ){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = "$ClientID"
            client_secret = "$ClientSecret"
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        $indicatorsuri = "https://api.securitycenter.windows.com/api/indicators"

        $AddIndicator = @{
            "indicatorValue"     = "$IndicatorValue";
            "indicatorType"      = "$IndicatorType";
            "action"             = "$Action";
            "application"        = "$Application";
            "title"              = "$Title";
            "description"        = "$Description";
            "expirationTime"     = "$expirationTime";
            "severity"           = "$severity";
            "recommendedActions" = "$recommendedActions"
        }

        If ([string]::IsNullOrEmpty($application)){
            $AddIndicator.Remove('application')
        }

        If ([string]::IsNullOrEmpty($recommendedActions)){
            $AddIndicator.Remove('recommendedActions')
        }

        If ([string]::IsNullOrEmpty($expirationTime)){
            $AddIndicator.Remove('expirationTime')
        }

        $AddIndicator = $AddIndicator | ConvertTo-Json
        Write-Verbose "Request body: $AddIndicator"

        if ($pscmdlet.ShouldProcess("$IndicatorValue", "Adding Indicator: $IndicatorType")){
            Try{
                $response = Invoke-WebRequest -Uri $indicatorsuri -Headers $Headers -Method Post -Body $AddIndicator
                If ($response.StatusCode -eq 200){
                    Write-Verbose "Indicator: $IndicatorType - $IndicatorValue was successfully added "
                    $True
                }
                Else{
                    Write-Warning "Adding Indicator: $IndicatorType - $IndicatorValue failed "
                    Write-Error "StatusCode: $($response.StatusCode)"
                    $False
                }
            }
            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)"
            }
        }
    }
    End{
        Write-Verbose "IndicatorType: $IndicatorType"
        Write-Verbose "IndicatorValue: $IndicatorValue"
        Write-Verbose "Severity; $Severity"
        Write-Verbose "StatusCode: $($response.statuscode)"
        Write-Verbose "StatusDescription: $($response.StatusDescription)"
    }
}

function Get-MDATPAlert{
    <#
    .Synopsis
    Get-MDATPAlert
 
    .Description
    Get-MDATPAlert retrieves Microsoft Defender Advanced Threat Protection alerts exposed through the Microsoft Defender Advanced Threat Protection Alerts Rest API.
 
    .PARAMETER Severity
    Provides an option to filter the output by Severity. Low, Medium, High.
 
    .PARAMETER PastHours
    Provides an option to filter the results by past hours when the alert was created.
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Get-WDATPAlert
 
    This command retrieves all alerts
 
    .EXAMPLE
    Get-MDATPAlert -PastHours 168 -Severity Informational
 
    This command retrieves all alerts from the past 7 days with severity level Informational
 
    .NOTES
    Version: 1.2
    Author: Alex Verboon
    Creation Date: 18.07.2020
    Purpose/Change: updated API uri
 
    #>

    [CmdletBinding()]
    Param(
        # Alert Severity level
        [Parameter(Mandatory=$false)]
        [ValidateSet('High', 'Medium', 'Low','Informational')]
        [String]$Severity,

        # Show alerts from past n hours
        [Parameter(Mandatory=$false)]
        [ValidateSet('12', '24', '48','72','168','720')]
        [String]$PastHours,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information

        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }

        # End Get API Information

        #WDATP Alerts - Europe
        $uri = "https://api.securitycenter.windows.com/api/alerts"
  
        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = "$ClientID"
            client_secret = "$ClientSecret"
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        $Headers = @{ Authorization = "Bearer $($Response.access_token)"}

    }
    Process{
        # Define the time range
        If ($null -eq $PastHours){
            $PastHours = 24
        }
        Else{
            $dateTime = (Get-Date).ToUniversalTime().AddHours(-$PastHours).ToString("o")
            $body = @{sinceTimeUtc = $dateTime}
        }

        # Retrieve MDATP alert data
        Try{
            $output = @(Invoke-RestMethod -Uri $uri -Headers $Headers -Body $Body -Method Get -Verbose -ContentType application/json)
        }
        Catch{
            $errorMessage = $_.Exception.Message
            Write-Error "Error retrieving MDATP alert data [$errorMessage]"
        }

        # Handle the output
        If ([string]::IsNullOrEmpty($Severity)){
            $output.value
        }
        Else{
            $output.value | Where-Object {$_.Severity -eq "$Severity"}
        }
    }
    End{
    }
}

function Get-MDATPCollectionPackageUri{
    <#
    .Synopsis
    Get-MDATPCollectionPackageUri
 
    .DESCRIPTION
    Get-MDATPCollectionPackageUri retrieves the Investigation Collection Package download URI and optionally download the package
 
    Use the Get-MDATPDeviceActions cmdlet to retrieve the ActionID of the investigation package collection request.
 
    .PARAMETER ActionID
    The Action ID of the investigation package collection request.
 
    .PARAMETER Download
    Downloads the investigation pacakge ZIP file into the users Downloads folder
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
 
    $lastcollectionrequestid = Get-MDATPDeviceActions -DeviceName testclient6 -ActionType CollectInvestigationPackage | Select-Object -First 1
    Get-MDATPCollectionPackageUri -ActionID $lastcollectionrequestid.id
 
    This comand first retrieves the last collection package request ID and then retrieves the download URI
 
    .EXAMPLE
    $lastcollectionrequestid = Get-MDATPDeviceActions -DeviceName testclient6 -ActionType CollectInvestigationPackage | Select-Object -First 1
    Get-MDATPCollectionPackageUri -ActionID $lastcollectionrequestid.id -Download
 
    This comand first retrieves the last collection package request ID and stores the investigation package into the users download folder
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 12.04.2020
    Purpose/Change: Initial script development
    #>


    [CmdletBinding()]
    Param(
        # ActionID
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$ActionID,

        # API Configuration
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile,

        # Download switch
        [switch]$Download
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri       = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID       = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret   = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }

        # MDATP API URI
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        # Define the request URI
        $MachineActionAPI = "$MDATP_API_URI/machineactions"
        $getPackageUri = "getPackageUri"
        $RequestURI = "$MachineActionAPI/$ActionID/$getPackageUri"
        Write-Verbose "Request URI: $($RequestURI)"

        # Let's get the Investigation Collection Package download URL
        Try{
            $URIresponse = @(Invoke-RestMethod -Uri "$RequestURI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
            $URIresponse.value
        }
        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)"
        }

        If($Download){
            $fileuri = $URIresponse.value
            $OutPutFile = "$ENV:USERPROFILE\Downloads\MDATP_InvestigationPackage_$($ActionID).zip"
            Try{
                Invoke-WebRequest -UseBasicParsing -Uri $fileuri -OutFile "$OutPutFile"
            }
            Catch{
                Write-Error "Investigation Package download failed"
            }
        }
    }
    End{}
}

function Get-MDATPDevice{
    <#
    .SYNOPSIS
    Get-MDATPDevice
 
    .DESCRIPTION
    Get-MDATPDevice retrieves MDATP device information
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER All
    Lists machine actions for all managed devices
 
    .PARAMETER HealthStatus
    Filters the results by device heatlh.
 
    .PARAMETER RiskScore
    Filters the results by device risk score
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
 
    .EXAMPLE
    Get-MDATPDevice -all
 
    This command retrieves all MDATP devices
 
    .EXAMPLE
    Get-MDATPDevice -All -HealthStatus Inactive
 
    This command lists all inactive devices
 
    .EXAMPLE
    Get-MDATPDevice -All -RiskScore Medium
 
    This command lists all devices with a medium risk score
 
    .EXAMPLE
 
    Get-MDATPDevice -DeviceName Computer01
 
    This command retrieves device information for Computer01
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 14.04.2020
    Purpose/Change: Initial script development
    #>


    [CmdletBinding()]
    Param(
        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Switch to retrieve actions from all devices
        [Parameter(Mandatory=$true,
            ParameterSetName='All')]
        [switch]$All,

        # The HealthStatus of the device
        [Parameter(Mandatory=$false,
            ParameterSetName='All')]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('Inactive','Active')]
        [String]$HealthStatus,

        # The device Risk Score
        [Parameter(Mandatory=$false,
            ParameterSetName='All')]
        [ValidateSet('None','Low','Medium','High')]
        [String]$RiskScore,

        # API Configuration
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings  = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri        = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID        = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret    = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }

        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        $DeviceUri = "https://api.securitycenter.windows.com/api/machines"

        If($PSBoundParameters.ContainsKey("HealthStatus")){
            $HealthFilter = "healthStatus eq '$Healthstatus'"
        }

        If($PSBoundParameters.ContainsKey("RiskScore")){
            $RiskFilter = "riskscore eq '$RiskScore'"
        }

        If ($HealthFilter -and $RiskFilter){
            $DeviceUri = $DeviceUri + "?`$filter=" + $HealthFilter + " and " + $RiskFilter
        }
        Elseif($HealthFilter){
            $DeviceUri = $DeviceUri + "?`$filter=" + $HealthFilter
        }
        ElseIf ($RiskFilter){
            $DeviceUri = $DeviceUri + "?`$filter="+$RiskFilter
        }


        If ($PSBoundParameters.ContainsKey("DeviceName")){
            $DeviceUri = $DeviceUri +  "?`$filter=" + "ComputerDNSName eq '$DeviceName'"
        }

        If ($PSBoundParameters.ContainsKey("DeviceID")){
            $DeviceUri = $DeviceUri +  "?`$filter=" + "id eq '$DeviceID'"
        }

        Write-Verbose "API Request: $DeviceUri"
        Try{
            $DeviceList = @(Invoke-RestMethod -Uri "$DeviceUri" -Headers $Headers -Method Get -Verbose -ContentType application/json)
            $Devicelist.value
        }
        Catch{
            $errorMessage = $_.Exception.Message
            Write-Error "Error retrieving MDATP device data [$errorMessage]"
        }
    }
    End{
    }
}



function Get-MDATPDeviceAction{
    <#
    .Synopsis
    Get-MDATPDeviceAction
 
    .DESCRIPTION
    Get-MDATPDeviceAction retrieves machine MDATP actions
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER All
    Lists machine actions for all managed devices
 
    .PARAMETER Action Type
    Filters the results by the specified Action type. Possible values are: RunAntiVirusScan, Offboard,UnrestrictCodeExecution,RestrictCodeExecution,Unisolate,Isolate,CollectInvestigationPackage,RequestSample,StopAndQuarantineFile
 
    .PARAMETER id
    The machine action id
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
        Get-MDATPDeviceAction -DeviceName computer02
 
        This command retrieves the actions for device 'computer02'
 
    .EXAMPLE
        Get-MDATPDeviceAction -DeviceID 70077ccc272ab3baeb991c09442c5657d22bfc5c
 
        This command retrieves the actions for the device with the specified device id
 
    .EXAMPLE
        Get-MDATPDeviceAction -ActionType CollectInvestigationPackage
 
        This command retreives all machine actions with the specified action type
 
    .EXAMPLE
        Get-MDATPDeviceAction -All
 
        This command retrieves machine actions for all devices
 
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 12.04.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding()]
    Param(
        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Switch to retrieve actions from all devices
        [Parameter(Mandatory=$true,
            ParameterSetName='All')]
        [switch]$All,

        # MDATP Action id
        [Parameter(Mandatory=$false,
            ParameterSetName='id')]
        [ValidateNotNullOrEmpty()]
        [String]$Id,

        # Action Type
        [Parameter(Mandatory=$false)]
        [ValidateSet('RunAntiVirusScan','Offboard','UnrestrictCodeExecution','RestrictCodeExecution','Unisolate','Isolate','CollectInvestigationPackage','RequestSample','StopAndQuarantineFile')]
        [String]$ActionType,

        # API Configuration
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }

        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{

        If ($DeviceName){
            $Machines = @()
            $DeviceName = $DeviceName.ToLower()
            $MachineAPI = "https://api.securitycenter.windows.com/api/machines" + "?`$filter=" + "ComputerDNSName eq '$DeviceName'"
            $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json) | Select-Object -ExpandProperty Value
            $ActionDevice = @($Machines)

            If($ActionDevice.count -gt 1){
                Write-Error "There are multiple device records with this computername, please specify the MDATP device id"
                $ActionDevice | Select-Object computerDnsName, id
            }
            Elseif($ActionDevice.count -eq 0){
                Write-Error "No device records found that match DeviceName $DeviceName"
            }
            Elseif ($ActionDevice.count -eq 1){
                Write-Verbose "$($ActionDevice.CompueterDnsName) found with id $($ActionDevice.id)"
                $DeviceID = $ActionDevice.id
            }
            Else{
                Write-Error "Something went wrong"
            }
        }


        if($DeviceID){
            $MachineAPI = "https://api.securitycenter.windows.com/api/machines/$DeviceID"
            $Machine = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
            If($Machine.Count -eq 1){
                $DeviceName = $Machine.ComputerDnsName
            }
            Else{
                Write-Error "No device records found that match DeviceID $DeviceID"
            }
        }

        # Get Machine Actions data
        $MachineActionsUri= "https://api-us.securitycenter.windows.com/api/machineactions/"
        if($PSBoundParameters.ContainsKey("All")){
            $MachineActionsUri= "https://api-us.securitycenter.windows.com/api/machineactions/"
        }
        Else{
            If($DeviceName){
                $MachineActionsUri = $MachineActionsUri + "?`$filter="
                $MachineActionsUri = $MachineActionsUri + "machineId+eq+'$DeviceID'"
            }

            If($ActionType){
                If($DeviceName){
                    $MachineActionsUri = $MachineActionsUri + "and type+eq+'$ActionType'"
                }
                Else{
                    $MachineActionsUri = $MachineActionsUri + "?`$filter="
                    $MachineActionsUri = $MachineActionsUri + "type+eq+'$ActionType'"
                }
            }
            # Search by action ID
            if($id){
                $MachineActionsUri = $MachineActionsUri + "$id"
            }
        }

        # Retrieve MDATP machine actions data
        Try{
            $output = @(Invoke-RestMethod -Uri $MachineActionsUri -Headers $Headers -Method Get -Verbose -ContentType application/json)
        }
        Catch{
            $errorMessage = $_.Exception.Message
            Write-Error "Error retrieving MDATP machine actions data [$errorMessage]"
        }

        # Handle the output
        If($id){
            $output
        }
        Else{
            $output.value
        }
    }
    End{}
}

function Get-MDATPDeviceTag{
    <#
    .Synopsis
    Get-MDATPDeviceTag
 
    .Description
    Get-MDATPDeviceTag retrieves tags assigned on the specified device
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
 
    .EXAMPLE
        Get-MDATPDeviceTag -DeviceName computer02
 
        This command reads all the tags assigned to the device 'computer02'
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 16.03.2020
    Purpose/Change: Initial script development
    #>


    [CmdletBinding()]
    Param(
        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Switch to retrieve tags from all devices
        [Parameter(Mandatory=$true,
            ParameterSetName='All')]
        [switch]$All,

        # API Configuration
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }

        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"
        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)

        If ($DeviceName){
            # change the devicename to lowercase
            $DeviceName = $DeviceName.ToLower()
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }
        Elseif($All){
            $ActionDevice = @($machines.value)
        }

        If($ActionDevice.Count -gt 0 -and $All -eq $true){
            $Result = ForEach($device in $ActionDevice){
                [PSCustomObject]@{
                    DeviceName  = $device.ComputerDnsName
                    id          = $device.id
                    machineTags = $device.machineTags
                }
            }
            $Result
        }
        ElseIf($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $Result = [PSCustomObject]@{
                DeviceName  = $ActionDevice.ComputerDnsName
                id          = $ActionDevice.id
                machineTags = $ActionDevice.machineTags
            }
            $Result
        }
    }
    End{}
}

function Get-MDATPEndpointStatus{
    <#
    .Synopsis
    Get-MDATPEndpointStatus
 
    .DESCRIPTION
    Get-MDATPEndpointStatus retrieves information about the Endpoint Status
 
    https://github.com/microsoft/Microsoft-365-Defender-Hunting-Queries/blob/master/General%20queries/Endpoint%20Agent%20Health%20Status%20Report.md
 
    This query will provide a report of many of the best practice configurations for Defender ATP deployment. Special Thanks to Gilad Mittelman for the initial inspiration and concept.
    Any tests which are reporting "BAD" as a result imply that the associated capability is not configured per best practice recommendation.
 
    Limitations
    1. The results will include a maximum of 100,000 rows.
    2. The number of executions is limited per tenant: up to 15 calls per minute, 15 minutes of running time every hour and 4 hours of running time a day.
    3. The maximal execution time of a single request is 10 minutes.
 
    .PARAMETER DeviceName
    Computername of the device.If no DeviceName is provided all devices are querried
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Get-MDATPEndpointStatus -DeviceName TestClient4
 
    .EXAMPLE
    Get-MDATPEndpointStatus
 
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 22.12.2020
    Purpose/Change: Initial script development
 
    #>

    [CmdletBinding()]
    Param
    (
        # Computername of the MDATP managed device
        [Parameter(Mandatory=$false)]
        [String]$DeviceName,

        # API Configuration
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )
    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri       = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID       = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret   = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
$kqlquery = @"
// Best practice endpoint configurations for Microsoft Defender for Endpoint deployment.
DeviceTvmSecureConfigurationAssessment
//DEVICENAME
| where ConfigurationId in ("scid-91", "scid-2000", "scid-2001", "scid-2002", "scid-2003", "scid-2010", "scid-2011", "scid-2012", "scid-2013", "scid-2014", "scid-2016")
| summarize arg_max(Timestamp, IsCompliant, IsApplicable) by DeviceId, DeviceName, ConfigurationId
| extend Test = case(
    ConfigurationId == "scid-2000", "SensorEnabled",
    ConfigurationId == "scid-2001", "SensorDataCollection",
    ConfigurationId == "scid-2002", "ImpairedCommunications",
    ConfigurationId == "scid-2003", "TamperProtection",
    ConfigurationId == "scid-2010", "AntivirusEnabled",
    ConfigurationId == "scid-2011", "AntivirusSignatureVersion",
    ConfigurationId == "scid-2012", "RealtimeProtection",
    ConfigurationId == "scid-91", "BehaviorMonitoring",
    ConfigurationId == "scid-2013", "PUAProtection",
    ConfigurationId == "scid-2014", "AntivirusReporting",
    ConfigurationId == "scid-2016", "CloudProtection",
    "N/A"),
    Result = case(IsApplicable == 0, "N/A", IsCompliant == 1, "GOOD", "BAD")
| extend packed = pack(Test, Result)
| summarize Tests = make_bag(packed) by DeviceId, DeviceName
| evaluate bag_unpack(Tests)
"@


        If ([string]::IsNullOrEmpty($DeviceName)){
            # nothing to do , we run the query against all devices
        }
        Else{
            $DeviceName = $DeviceName.ToLower()
            $replacestring = "| where DeviceName == '$DeviceName'"
            $kqlquery = $kqlquery.Replace("//DEVICENAME","$replacestring")
        }
        $uri = "https://api.securitycenter.windows.com/api/advancedqueries/run"
        $body = ConvertTo-Json -InputObject @{ 'Query' = $kqlquery}
        Try{
            $webResponse = @(Invoke-WebRequest -Method Post -Uri $uri -Headers $headers -Body $body)
            $response =  $webResponse | ConvertFrom-Json
            $results = $response.Results
            $results
        }
        Catch{
            $errorMessage = $_.Exception.Message
            Write-Error "Error running advanced hunting query [$errorMessage]"
        }
    }
    End{
        Write-Verbose "Schema: $Schema"
        Write-Verbose "Device: $DeviceTarget"
        Write-Verbose "Query: $ExecQuery"
        Write-Verbose "Retrieved $($results.count) records"
    }
}

function Get-MDATPIndicator{
    <#
    .Synopsis
    Get-MDATPIndicator
 
    .DESCRIPTION
    Get-MDATPIndicator retrieves Microsoft Defender Advanced Threat Protection custom indicators exposed
    through the Microsoft Defender Advanced Threat Protection indicators Rest API.
 
    .PARAMETER IndicatorType
    Filters the indicator by the specified IndicatorType. Possible values are: DomainName, Url, FileSha256,IpAddress,WebCategory
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Get-MDATPIndicator
 
    This command retrieves all TI indicators
 
    .EXAMPLE
    Get-MDATPIndicator -IndicatorType DomainName
 
    This command retrieves all DomainName TI indicators
 
    .EXAMPLE
        $indicators = Get-MDATPIndicator -MTPConfigFile "C:\Dev\Private\MSSecurityPowerShell\Config\PoshMTPconfigBaseVISION.json"
        $indicators | Where-Object {$_.Source -like "WindowsDefenderATPThreatIntelAPI"}
 
        This sample shows how to filter results by TI source
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 20.03.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding()]
    Param(
        # Indicator type
        [Parameter(Mandatory=$false)]
        [ValidateSet('DomainName','Url','FileSha256','IpAddress','WebCategory')]
        [String]$IndicatorType,

        # MDATP configfile
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        Try{
            $indicatorsuri = "https://api.securitycenter.windows.com/api/indicators"
            $indicators = @(Invoke-RestMethod -Uri $indicatorsuri -Headers $Headers -Body $Body -Method Get -Verbose -ContentType application/json)

        }
        Catch{
            $errorMessage = $_.Exception.Message
            Write-Error "Error retrieving MDATP TI indicators data [$errorMessage]"
        }

        If ($IndicatorType){
            $indicators.value | Where-Object {$_.IndicatorType -eq "$IndicatorType"}
        }
        Else{
            $indicators.value
        }
    }
    End{}
}

function Get-MDATPInvestigation{
    <#
    .Synopsis
    Get-MDATPInvestigation
 
    .DESCRIPTION
    Get-MDATPInvestigation retrieves Microsoft Defender ATP automated investigation information
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER id
    The investigation id
 
    .PARAMETER State
    The current state of the investigation. Possible values are:
    Unknown, Terminated, SuccessfullyRemediated, Benign, Failed, PartiallyRemediated, Running, PendingApproval, PendingResource, PartiallyInvestigated, TerminatedByUser, TerminatedBySystem, Queued, InnerFailure, PreexistingAlert, UnsupportedOs, UnsupportedAlertType, SuppressedAlert
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Get-MDATPInvestigation
 
    This command retrieves all investigations
 
    .EXAMPLE
    Get-MDATPInvestigation -DeviceName Computer01
 
    This command retrieves all investigations for Computer01
 
    .EXAMPLE
    Get-MDATPInvestigation -DeviceID 70077ccc272ab3baeb991c09442c5657d22bfc5c
 
    This command retrieves all investigations for the device with the specified
    device id.
 
    .EXAMPLE
    Get-MDATPInvestigation -State Running
 
    This command retireves all investigations with the state Running
 
    .EXAMPLE
    Get-MDATPInvestigation -Id 12
 
    This command retrieves investigation details for the investigation with id 12
 
    .EXAMPLE
    Get-MDATPInvestigation -DeviceName computer01 -State SuccessfullyRemediated
 
    This command retrieves all SuccessfullyRemediated investigations for device computer01
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 12.04.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding(DefaultParametersetname="All")]
    Param(
        # Switch to list all devices
        [Parameter(Mandatory=$false,
            ParameterSetName='All')]
        [ValidateNotNullOrEmpty()]
        [switch]$All,

        # Computername of the MDATP managed device
        [Parameter(Mandatory=$false,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$false,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # MDATP investigation id
        [Parameter(Mandatory=$false,
            ParameterSetName='id')]
        [ValidateNotNullOrEmpty()]
        [String]$Id,

        # Investigation state
        [Parameter(Mandatory=$false)]
        [ValidateSet(  'Unknown','Terminated','SuccessfullyRemediated','Benign','Failed','PartiallyRemediated','Running','PendingApproval','PendingResource','PartiallyInvestigated','TerminatedByUser','TerminatedBySystem','Queued','InnerFailure','PreexistingAlert','UnsupportedOs','UnsupportedAlertType','SuppressedAlert')]
        [String]$State,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API access configuration
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings  = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri        = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID        = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret    = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{

        If ($DeviceName){
            $MachineAPI = "https://api.securitycenter.windows.com/api/machines"
            $DeviceName = $DeviceName.ToLower()
            $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
            $ActionDevice = @($machines.value | Select-Object -Property *  | Where-Object {$_.computerDnsName -like "$DeviceName"})

            If($ActionDevice.count -gt 1){
                Write-Error "There are multiple device records with this computername, please specify the MDATP device id"
                $ActionDevice | Select-Object computerDnsName, id
            }
            Elseif($ActionDevice.count -eq 0){
                Write-Error "No device records found that match DeviceName $DeviceName"
            }
            Elseif ($ActionDevice.count -eq 1){
                Write-Verbose "$($ActionDevice.CompueterDnsName) found with id $($ActionDevice.id)"
                $DeviceID = $ActionDevice.id
            }
        }

        if($DeviceID){
            $MachineAPI = "https://api.securitycenter.windows.com/api/machines/$DeviceID"
            $Machine = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
            If($Machine.Count -eq 1){
                $DeviceName = $Machine.ComputerDnsName
            }
            Else{
                Write-Error "No device records found that match DeviceID $DeviceID"
            }
        }

        # Get Investigation data
        $InvestigationUri= "https://api-us.securitycenter.windows.com/api/investigations/"
        if($PSBoundParameters.ContainsKey("All")){
            $InvestigationUri= "https://api-us.securitycenter.windows.com/api/investigations/"
        }
        Else{
            If($DeviceName){
                $InvestigationUri = $InvestigationUri + "?`$filter="
                $InvestigationUri = $InvestigationUri + "machineId+eq+'$DeviceID'"
            }

            If($State){
                If($DeviceName){
                    $InvestigationUri = $InvestigationUri + "and state+eq+'$State'"
                }
                Else{
                    $InvestigationUri = $InvestigationUri + "?`$filter="
                    $InvestigationUri = $InvestigationUri + "state+eq+'$State'"
                }
            }

            # Search by Investigation ID
            if($id){
                $InvestigationUri = $InvestigationUri + "$id"
            }
        }
        # Retrieve MDATP Investigations data
        Try{
            $output = @(Invoke-RestMethod -Uri $InvestigationUri -Headers $Headers -Method Get -Verbose -ContentType application/json)
        }
        Catch{
            $errorMessage = $_.Exception.Message
            Write-Error "Error retrieving MDATP inestigation data [$errorMessage]"
        }

        # Handle the output
        If($id){
            $output
        }
        Else{
            $output.value
        }
    }
    End{}
}

function Get-MDATPQuery{
    <#
    .Synopsis
    Get-MDATPQuery
 
    .DESCRIPTION
    Get-MDATPQuery executes MDATP advanced hunting queries through the
    Microsoft Defender Advanced Threat Protection Alerts Rest API.
 
    Limitations
    1. You can only run a query on data from the last 30 days.
    2. The results will include a maximum of 100,000 rows.
    3. The number of executions is limited per tenant: up to 15 calls per minute, 15 minutes of running time every hour and 4 hours of running time a day.
    4. The maximal execution time of a single request is 10 minutes.
 
    .PARAMETER Schema
    The Schema to use for the query
 
    .PARAMETER DeviceName
    Computername of the device.If no DeviceName is provided all devices are querried
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Get-MDATPQuery -Schema DeviceLogonEvents -DeviceName TestClient4
 
    The above query retrieves all logon events for the specified device
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 17.02.2020
    Purpose/Change: Initial script development
 
    #>

    [CmdletBinding()]
    Param
    (
        # The MDATP Schema to search for
        [Parameter(Mandatory=$true)]
        [ValidateSet('DeviceAlertEvents','DeviceInfo','DeviceNetworkInfo','DeviceProcessEvents','DeviceFileEvents','DeviceRegistryEvents','DeviceLogonEvents','DeviceImageLoadEvents','DeviceEvents')]
        [String]$Schema,

        # Computername of the MDATP managed device
        [Parameter(Mandatory=$false)]
        [String]$DeviceName,

        # The Time Range
        [Parameter(Mandatory=$false)]
        [ValidateSet('1h', '12h', '1d','7d','30d')]
        [String]$TimeRange,

        # API Configuration
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri       = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID       = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret   = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        #WDATP API
        $uri = "https://api.securitycenter.windows.com/api/advancedqueries/run"
        # Define devices to include in query
        if ($DeviceName){
            $DeviceName = $DeviceName.ToLower()
            $ExecQuery = "$Schema | where DeviceName == '$DeviceName'"
        }
        Else{
            $ExecQuery = "$Schema"
        }
        $DeviceTarget = if([string]::IsNullOrEmpty($DeviceName)) {"All Devices"}Else {"$DeviceName"}

        If ($TimeRange){
            $ExecQuery = $ExecQuery + "|where Timestamp > ago($($TimeRange))"
        }


        Try{
            $body = ConvertTo-Json -InputObject @{ 'Query' = $ExecQuery}
            $webResponse = @(Invoke-WebRequest -Method Post -Uri $uri -Headers $headers -Body $body)
            $response =  $webResponse | ConvertFrom-Json
            $results = $response.Results
            $results
        }
        Catch{
            $errorMessage = $_.Exception.Message
            Write-Error "Error running advanced hunting query [$errorMessage]"
        }
    }
    End{
        Write-Verbose "Schema: $Schema"
        Write-Verbose "Device: $DeviceTarget"
        Write-Verbose "Query: $ExecQuery"
        Write-Verbose "Retrieved $($results.count) records"
    }
}

function Get-MDATPTvmRecommendation{
    <#
    .Synopsis
    Get-MDATPTvmRecommendation
 
    .DESCRIPTION
    Get-MDATPTvmRecommendation retrieves Microsoft Defender Advanced Threat Protection Threat and Vulnerability Management
    security recommendations
 
    .PARAMETER recommendationCategory
     
    Category or grouping to which the configuration belongs: Application, OS, Network, Accounts, Security controls
     
    .PARAMETER publicexploit
 
    Setting this parameter limits the results to security recommendations that address a public exploit
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Get-MDATPTvmRecommendation
 
    This command retrieves all TVM security recommendations
 
    .EXAMPLE
        $tvmrecommendations = Get-MDATPTvmRecommendation -MTPConfigFile "C:\Users\Alex\Documents\WindowsPowerShell\Modules\PSMDATP\PoshMTPconfig.json"
         
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 18.07.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding()]
    Param(
        # recommendation Category
        [Parameter(Mandatory=$false)]
        [ValidateSet('DomainName','Application','OS','Network','Accounts','Security controls')]
        [String]$recommendationCategory,


        # publicexploit
        [Parameter(Mandatory=$false)]
        [switch]$publicexploit,

        # MDATP configfile
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        Try{
            $tvmuri = "https://api.securitycenter.windows.com/api/recommendations"
            $tvmrecommendations = @(Invoke-RestMethod -Uri $tvmuri -Headers $Headers -Body $Body -Method Get -Verbose -ContentType application/json)

        }
        Catch{
            $errorMessage = $_.Exception.Message
            Write-Error "Error retrieving MDATP TVM security recommendations data [$errorMessage]"
        }
        
        If ($recommendationCategory){
            $Result = $tvmrecommendations.value | Where-Object {$_.recommendationCategory -eq "$recommendationCategory"}
        }
        Else{
            $Result = $tvmrecommendations.value
        }

        If ($publicexploit){
            $Result = $Result | Where-Object {$_.publicExploit -eq $true}
        }

        $Result


    }
    End{}
}

function Get-MDATPTvmVulnerability{
    <#
    .Synopsis
    Get-MDATPTvmVulnerability
 
    .DESCRIPTION
    Get-MDATPTvmVulnerability retrieves Microsoft Defender Advanced Threat Protection Threat and Vulnerability Management
    vulnerability informaition
 
    .PARAMETER Severity
     
    Severity level assigned to the security vulnerability based on the CVSS score and dynamic factors influenced by the threat landscape
    Low, Medium, High, Critical
     
    .PARAMETER IsExploitAvailable
 
    Setting this parameter limits the results to vulnerabilities where exploit code for the vulnerability is publicly available
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Get-MDATPTvmVulnerability
 
    This command retrieves all TVM vulnerability information
 
    .EXAMPLE
        $tvmvulninfo = Get-MDATPTvmVulnerability -MTPConfigFile "C:\Users\Alex\Documents\WindowsPowerShell\Modules\PSMDATP\PoshMTPconfig.json"
         
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 18.07.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding()]
    Param(
        # Severity level
        [Parameter(Mandatory=$false)]
        [ValidateSet('Low','Medium','High','Critical')]
        [String]$SeverityLevel,


        # publicexploit
        [Parameter(Mandatory=$false)]
        [switch]$IsExploitAvailable,

        # MDATP configfile
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        Try{
            $tvmuri = "https://api.securitycenter.windows.com/api/vulnerabilities"
            $tvmrVulnInfo = @(Invoke-RestMethod -Uri $tvmuri -Headers $Headers -Body $Body -Method Get -Verbose -ContentType application/json)

        }
        Catch{
            $errorMessage = $_.Exception.Message
            Write-Error "Error retrieving MDATP TVM vulnerability data [$errorMessage]"
        }
        
        If ($Severity){
            $Result = $tvmrVulnInfo.value | Where-Object {$_.VulnerabilitySeverityLevel -eq "$Severity"}
        }
        Else{
            $Result = $tvmrVulnInfo.value
        }

        If ($IsExploitAvailable){
            $Result = $Result | Where-Object {$_.publicExploit -eq $true}
        }

        $Result


    }
    End{}
}

function Remove-MDATPDevice{
    <#
    .Synopsis
    Remove-MDATPDevice
 
    .DESCRIPTION
    Remove-MDATPDevice offboards a device from MDATP and adds a tag 'Offboarded' to the device.
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER OffboardReason
    Comment to be added to the offboard action, when no value is specified a default comment 'Offobard machine by automation' is added
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Remove-MDATPDevice -DeviceName Computer02
 
    This command offboards device Computer02 from MDATP
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 14.03.2020
    Purpose/Change: Initial script development
 
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param(
        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Offboard reason
        [Parameter(Mandatory=$false)]
        [String]$OffboardReason = "Offobard machine by automation",

        # API Configuration
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings   = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri         = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID         = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret     = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        # MDATP API URI
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"
        $OffboardingStatus = $false

        # change the devicename to lowercase
        $DeviceName = $DeviceName.ToLower()

        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
        If ($DeviceName){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }

        If($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $MDATPDeviceID = $ActionDevice.id
            # set offboarding comment
            $OffboardReasonInput = @{"Comment" = "$OffboardReason"} | ConvertTo-Json
            if ($pscmdlet.ShouldProcess("$DeviceName", "offobarding device from MDATP")){
                $Offboarduri = "$MachineAPI/$MDATPDeviceID/offboard"
                Try{
                    $OffboardAction  =Invoke-WebRequest -Uri $Offboarduri -Headers $Headers -Method Post -Body $OffboardReasonInput
                    If ($OffboardAction.StatusCode -eq 201){
                        Write-Verbose "Offboarding device $DeviceName completed successfully"
                        # Tag machine
                        $offboardTag = @{"Value" = "Offboarded"; "Action"= "Add"} | ConvertTo-Json
                        $Taguri = "$MachineAPI/$MDATPDeviceID/tags"
                        Invoke-WebRequest -Uri $Taguri -Headers $Headers -Method Post -Body $offboardTag
                        $OffboardingStatus = $true
                        # end tag machine
                        $True
                    }
                    Else{
                        Write-Warning "Offboarding device $DeviceName failed!"
                        Write-Error "StatusCode: $($OffboardAction.StatusCode)"
                        $OffboardingStatus = $false
                    }
                }
                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)"
                }
            }
        }
    }
    End{
        Write-Verbose "Device: $DeviceName"
        Write-Verbose "DeviceID: $MDATPDeviceID"
        Write-Verbose "Reason: $OffboardReason"
        Write-Verbose "Offboardingstatus: $OffboardingStatus"
        Write-Verbose "StatusCode: $($response.statuscode)"
        Write-Verbose "StatusDescription: $($response.StatusDescription)"
    }
}

function Remove-MDATPDeviceTag{
    <#
    .Synopsis
    Remove-MDATPDeviceTag
 
    .Description
    Remove-MDATPDeviceTag removes the specified Tag to the MDATP device.
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER Tag
    The value of the tag to be removed
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
 
    .EXAMPLE
    Remove-MDATPDeviceTag -DeviceName computer02 -Tag 'Testing' -verbose
 
    This command removes the tag 'testing' from device 'computer02'
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 16.03.2020
    Purpose/Change: Initial script development
    #>


    [CmdletBinding(SupportsShouldProcess)]
    Param(

        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Tag to be removed from the device
        [Parameter(Mandatory=$true)]
        [String]$Tag,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )
    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings     = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri           = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID           = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret       = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        # MDATP API URI
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"

        # change the devicename to lowercase
        $DeviceName = $DeviceName.ToLower()

        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
        If ($DeviceName){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }

        If($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $MDATPDeviceID = $ActionDevice.id
            if ($pscmdlet.ShouldProcess("$DeviceName", "Remvoing tag: $Tag")){
                Try{
                    # Tag machine
                    $AddTag = @{"Value" = "$Tag"; "Action"= "Remove"} | ConvertTo-Json
                    $Taguri = "$MachineAPI/$MDATPDeviceID/tags"
                    $response  =Invoke-WebRequest -Uri $Taguri -Headers $Headers -Method Post -Body $AddTag
                    # end tag machine
                    If ($response.StatusCode -eq 200){
                        Write-Verbose "Tag: $Tag was successfully removed from device $DeviceName"
                        $True
                    }
                    Else{
                        Write-Warning "Removing tag $Tag from device $DeviceName failed!"
                        Write-Error "StatusCode: $($response.StatusCode)"
                        $false
                    }
                }
                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)"
                }
            }
        }
    }
    End{
        Write-Verbose "Device: $DeviceName"
        Write-Verbose "DeviceID: $MDATPDeviceID"
        Write-Verbose "Removed tag: $Tag"
        Write-Verbose "StatusCode: $($response.statuscode)"
        Write-Verbose "StatusDescription: $($response.StatusDescription)"
    }
}

function Remove-MDATPIndicator{
    <#
    .Synopsis
    Remove-MDATPIndicator
 
    .DESCRIPTION
    Remove-MDATPIndicator removes a custom indicator from the Microsoft Defender ATP
    instance
         
    .PARAMETER IndicatorID
    The unique custom indicator ID
     
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Remove-MDATPIndicator -IndicatorID 25
 
    This command removes the custom indicator with id 25
     
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 05.05.2020
    Purpose/Change: Initial script development
 
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param(
        # Unique custom indicator ID
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ValidateRange(1,150000)]
        [int]$IndicatorID,

        # API Configuration
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings   = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri         = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID         = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret     = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        Try{
            $indicatorsuri = "https://api.securitycenter.windows.com/api/indicators"
            $indicators = @(Invoke-RestMethod -Uri $indicatorsuri -Headers $Headers -Body $Body -Method Get -Verbose -ContentType application/json)
        }
        Catch{
            $errorMessage = $_.Exception.Message
            Write-Error "Error retrieving MDATP TI indicators data [$errorMessage]"
        }

        $IndicatorInfo = $indicators.value | Where-Object {$_.id -eq $IndicatorID}
        $RemoveIndicatorsuri = "https://api.securitycenter.windows.com/api/indicators/$IndicatorID"

        if ($pscmdlet.ShouldProcess("$IndicatorID", "Remvoing Indicator - $($IndicatorInfo.IndicatorType) - $($IndicatorInfo.indicatorvalue)")){
            Try{
                $response = Invoke-WebRequest -Uri $RemoveIndicatorsuri -Headers $Headers -Method Delete
                If ($response.StatusCode -eq 204){
                    Write-Verbose "Indicator: $IndicatorID - $($IndicatorInfo.IndicatorType) - $($IndicatorInfo.indicatorvalue) was successfully removed"
                    $True
                }
                Else{
                    Write-Warning "Removing Indicator: $IndicatorID failed"
                    Write-Error "StatusCode: $($response.StatusCode)"
                    $False
                }
            }
            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)"
            }
        }
    }
    End{
        Write-Verbose "IndicatorID: $IndicatorID"
        Write-Verbose "IndicatorType: $($IndicatorInfo.indicatorType)"
        Write-Verbose "Indicatorvalue: $($IndicatorInfo.indicatorValue)"
        Write-Verbose "StatusCode: $($response.statuscode)"
        Write-Verbose "StatusDescription: $($response.StatusDescription)"
    }
}

function Set-MDATPAlert{
    <#
    .Synopsis
    Set-MDATPAlert
 
    .Description
    Set-MDATPAlert updates a Microsoft Defender Advanced Threat Protection alert through the Microsoft Defender Advanced Threat Protection Alerts Rest API.
 
    .PARAMETER AlertID
    Identity of the Indicator entity. Required
     
    .PARAMETER status
    The status that will be set for the alert in the organization. Possible values are: "New", "InProgress", and "Resolved". Optional
 
    .PARAMETER assignedTo
    The userid that will be set for assigned to field for the the alert in the organization. Example: secop2@contoso.com. Optional
 
    .PARAMETER classification
    The classification that will be set for the alert in the organization. Possible values are: "Unknown", "FalsePositive", and "TruePositive". Optional
 
    .PARAMETER determination
    The determination that will be set for the alert in the organization. Possible values are: "NotAvailable", "Apt", "Malware", "SecurityPersonnel", "SecurityTesting", "UnwantedSoftware", and "Other". Optional
 
    .PARAMETER comments
    The comment field that will be set for the the alert in the organization. Optional
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Set-WDATPAlert -AlertID 121688558380765161_2136280442 -status Resolved -assignedTo secop2@contoso.com -classification FalsePositive -determination Malware -comments "Resolve my alert and assign to secop2
     
    .NOTES
    Version: 1.0
    Author: Daniel Lacher
    Creation Date: 02.11.2020
    Purpose/Change: Initial pass at creation of function to allow for update to MDATP Alerts via API and PSMDATP framework.
 
    #>

    [CmdletBinding(SupportsShouldProcess=$true)]
    Param(
        # MDATP Alert ID.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [String]$AlertID,

        # Specifies the current status of the alert. The property values are: 'New', 'InProgress' and 'Resolved'.
        [Parameter(Mandatory=$false)]
        [ValidateSet('New', 'InProgress','Resolved')]
        [String]$status,

        # Owner of the alert.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullorEmpty()]
        [String]$assignedTo,

        # Specifies the specification of the alert. The property values are: 'Unknown', 'FalsePositive', 'TruePositive'.
        [Parameter(Mandatory=$false)]
        [ValidateSet('Unknown', 'FalsePositive', 'TruePositive')]
        [String]$classification,

        # Specifies the determination of the alert. The property values are: 'NotAvailable', 'Apt', 'Malware', 'SecurityPersonnel', 'SecurityTesting', 'UnwantedSoftware', 'Other'.
        [Parameter(Mandatory=$false)]
        [ValidateSet('NotAvailable', 'Apt', 'Malware', 'SecurityPersonnel', 'SecurityTesting', 'UnwantedSoftware', 'Other')]
        [String]$determination,

        # Comment to be added to the alert.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullorEmpty()]
        [String]$comments,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = "$ClientID"
            client_secret = "$ClientSecret"
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body


        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }

    Process{

        $alertsuri = "https://api.securitycenter.windows.com/api/alerts/$AlertID"
        $UpdateAlert = @{
            "status"         = "$status"
            "assignedTo"     = "$assignedTo"
            "classification" = "$classification"
            "determination"  = "$determination"
            "comment"        = "$comments"
        }

        $UpdateAlert = $UpdateAlert | ConvertTo-Json
        Write-Verbose "Request body: $UpdateAlert"

        if ($pscmdlet.ShouldProcess("$AlertID", "Updating Alert: $AlertID")){
            Try{
                $response = Invoke-WebRequest -Uri $alertsuri -Headers $Headers -Method Patch -Body $UpdateAlert
                If ($response.StatusCode -eq 200){
                    Write-Verbose "Alert: $AlertID - was successfully updated "
                    $True
                }
                Else{
                    Write-Warning "Alert: $AlertID - update failed"
                    Write-Error "StatusCode: $($response.StatusCode)"
                    $False
                }
            }
            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)"
            }
        }
    }
    End{
        Write-Verbose "AlertID: $AlertID";
        Write-Verbose "Status: $status";
        Write-Verbose "AssignedTo:$assignedTo";
        Write-Verbose "Classification: $classification";
        Write-Verbose "Determination: $determination";
        Write-Verbose "Comments: $comments"
    }
}

function Start-MDATPAppRestriction{
    <#
    .Synopsis
    Start-MDATPAppRestriction
 
    .DESCRIPTION
    Start-MDATPAppRestriction restricts execution of all applications on the machine.
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER Comment
    Comment that is added to the request, if no comment is provided the default commment 'submitted by automation' is used.
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Start-MDATPAppRestriction -DeviceName computer02 -Comment "incident1973"
 
    This command restricts application execution on device computer02
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 12.04.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param(
        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Comment for the request
        [Parameter(Mandatory=$false)]
        [String]$Comment,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings  = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri        = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID        = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret    = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        # MDATP API URI
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"

        If([string]::IsNullOrEmpty($Comment)){
            $Comment = "submitted by automation"
        }

        # change the devicename to lowercase
        $DeviceName = $DeviceName.ToLower()

        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
        If ($DeviceName){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }

        If($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $MDATPDeviceID = $ActionDevice.id

            if ($pscmdlet.ShouldProcess("$DeviceName", "Start Isolation: $IsolationType")){
                Try{
                    $AppRestrictionInput = @{"Comment" = "$Comment"} | ConvertTo-Json
                    $AppRestrictionUri = "$MachineAPI/$MDATPDeviceID/restrictCodeExecution "
                    $AppRestrictionResponse  =Invoke-WebRequest -Uri $AppRestrictionUri -Headers $Headers -Method Post -Body $AppRestrictionInput
                    If ($AppRestrictionResponse.StatusCode -eq 201){
                        $ActionID = $AppRestrictionResponse.content | ConvertFrom-Json | Select-Object -ExpandProperty id
                        Write-Verbose "App restriction was successfully initiated for device $DeviceName -ActionID: $ActionID"
                        $ActionID
                    }
                    Else{
                        $ActionID = "0000000-0000-0000-0000-000000000000"
                        Write-Warning "Initiating app restriction for device $DeviceName failed!"
                        Write-Error "StatusCode: $($AppRestrictionResponse.StatusCode)"
                        $ActionID
                    }
                }
                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)"
                    $ActionID = "0000000-0000-0000-0000-000000000000"
                    $ActionID
                }
            }
        }
    }
    End{
        Write-Verbose "Device: $DeviceName"
        Write-Verbose "DeviceID: $MDATPDeviceID"
        Write-Verbose "Comment: $Comment"
        Write-Verbose "ActionID: $($ActionID)"
        Write-Verbose "StatusCode: $($IsolateResponse.statuscode)"
        Write-Verbose "StatusDescription: $($IsolateResponse.StatusDescription)"
    }
}

function Start-MDATPAVScan{
    <#
    .Synopsis
    Start-MDATPAVScan
 
    .DESCRIPTION
    Start-MDATPAVScan initiates an Antivirus scan on the specified device
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER Scantype
    The type of scan to perform, Full or Quick
 
    .PARAMETER Comment
    Comment that is added to the request, if no comment is provided the default commment 'submitted by automation' is used.
 
   .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Start-MDATPAVScan -DeviceName testclient6 -ScanType Quick -Comment "better check"
 
    This command starts a quck AV scan on device testclient6
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 17.03.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param(

        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # ScanType controls the type of scan to perform
        [Parameter(Mandatory=$true)]
        [ValidateSet('Quick','Full')]
        [String]$ScanType,

        # Comment for the request
        [Parameter(Mandatory=$false)]
        [String]$Comment,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }

        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token
        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        # MDATP API URI
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"

        If([string]::IsNullOrEmpty($Comment)){
            $Comment = "submitted by automation"
        }

        $DeviceName = $DeviceName.ToLower()
        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
        If ($DeviceName){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }

        If($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $MDATPDeviceID = $ActionDevice.id
            if ($pscmdlet.ShouldProcess("$DeviceName", "Start AV Scan: $ScanType")){
                Try{
                    # DefineScanType
                    $ScanTypeInput = @{"ScanType" = "$ScanType"; "Comment"= "$Comment"} | ConvertTo-Json
                    $ScanUri = "$MachineAPI/$MDATPDeviceID/runAntiVirusScan"
                    $ScanResponse  =Invoke-WebRequest -Uri $ScanUri -Headers $Headers -Method Post -Body $ScanTypeInput
                    # end tag machine
                    If ($ScanResponse.StatusCode -eq 201){
                        $ActionID = $ScanResponse.content | ConvertFrom-Json | Select-Object -ExpandProperty id
                        Write-Verbose "$ScanType scan was successfully initiated for device $DeviceName"
                        $ActionID
                    }
                    Else{
                        $ActionID = "0000000-0000-0000-0000-000000000000"
                        Write-Warning "Initiating $ScanType scan for device $DeviceName failed!"
                        Write-Error "StatusCode: $($ScanResponse.StatusCode)"
                        $ActionID
                    }
                }
                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)"
                    $ActionID = "0000000-0000-0000-0000-000000000000"
                    $ActionID
                }
            }
        }
    }
    End{
        Write-Verbose "Device: $DeviceName"
        Write-Verbose "DeviceID: $MDATPDeviceID"
        Write-Verbose "ScanType: $ScanType"
        Write-Verbose "Comment: $Comment"
        Write-Verbose "ActionID: $($ActionID)"
        Write-Verbose "StatusCode: $($ScanResponse.statuscode)"
        Write-Verbose "StatusDescription: $($ScanResponse.StatusDescription)"
    }
}

function Start-MDATPInvestigation{
    <#
    .Synopsis
    Start-MDATPInvestigation
 
    .DESCRIPTION
    Start-MDATPInvestigation initiates an automated investigation on the targeted device
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER Comment
    Comment that is added to the request, if no comment is provided the default commment 'submitted by automation' is used.
    Comment to associate with the action
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Start-MDATPInvestigation -DeviceName computer02 -Comment "incident1973"
 
    This command starts an automated investigation on device computer02
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 17.03.2020
    Purpose/Change: Initial script development
    #>


    [CmdletBinding(SupportsShouldProcess)]
    Param(

        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Comment for the request
        [Parameter(Mandatory=$false)]
        [String]$Comment,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }

        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        # MDATP API URI
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"

        If([string]::IsNullOrEmpty($Comment)){
            $Comment = "submitted by automation"
        }

        $DeviceName = $DeviceName.ToLower()
        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
        If ($DeviceName){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }

        If($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $MDATPDeviceID = $ActionDevice.id
            if ($pscmdlet.ShouldProcess("$DeviceName", "Start automated investigation")){
                Try{
                    $InvestigationInput = @{"Comment" = "$Comment"} | ConvertTo-Json
                    $InvestigationUri = "$MachineAPI/$MDATPDeviceID/startInvestigation"
                    $InvestigationResponse = Invoke-WebRequest -Uri $InvestigationUri -Headers $Headers -Method Post -Body $InvestigationInput
                    If ($InvestigationResponse.StatusCode -eq 201){
                        $ActionID = $InvestigationResponse.content | ConvertFrom-Json | Select-Object -ExpandProperty id
                        Write-Verbose "An automated investigation was successfully initiated for device $DeviceName -ActionID: $ActionID"
                        $ActionID
                    }
                    Else{
                        $ActionID = "0000000-0000-0000-0000-000000000000"
                        Write-Warning "Initiating automated investigation for device $DeviceName failed!"
                        Write-Error "StatusCode: $($InvestigationResponse.StatusCode)"
                        $ActionID
                    }
                }
                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)"
                    $ActionID = "0000000-0000-0000-0000-000000000000"
                    $ActionID
                }
            }
        }
    }
    End{
        Write-Verbose "Device: $DeviceName"
        Write-Verbose "DeviceID: $MDATPDeviceID"
        Write-Verbose "Comment: $Comment"
        Write-Verbose "ActionID: $($ActionID)"
        Write-Verbose "StatusCode: $($InvestigationResponse.statuscode)"
        Write-Verbose "StatusDescription: $($InvestigationResponse.StatusDescription)"
    }
}

function Start-MDATPInvestigationPackageCollection{
    <#
    .Synopsis
    Start-MDATPInvestigationPackageCollection
 
    .Description
    Start-MDATPInvestigationPackageCollection initiates the collection of an investigation package
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER Comment
    Comment that is added to the request, if no comment is provided the default commment 'submitted by automation' is used.
 
   .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Start-MDATPInvestigationPackageCollection -DeviceName computer02
 
    This command starts the collection of the investigation package on device computer02
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 17.03.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param(

        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Comment for the request
        [Parameter(Mandatory=$false)]
        [String]$Comment,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token

        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"

        If([string]::IsNullOrEmpty($Comment)){
            $Comment = "submitted by automation"
        }
        $DeviceName = $DeviceName.ToLower()

        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
        If ($DeviceName){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }

        If($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $MDATPDeviceID = $ActionDevice.id
            if ($pscmdlet.ShouldProcess("$DeviceName", "Start investigation package collection")){
                Try{
                    Write-Verbose "Device: $DeviceName Id:$MDATPDeviceID"
                    $CollectInput = @{"Comment" = "$Comment"} | ConvertTo-Json
                    $CollectUri = "$MachineAPI/$MDATPDeviceID/collectInvestigationPackage"
                    $CollectResponse  =Invoke-WebRequest -Uri $CollectUri -Headers $Headers -Method Post -Body $CollectInput
                    # end tag machine
                    If ($CollectResponse.StatusCode -eq 201){
                        $ActionID = $CollectResponse.content | ConvertFrom-Json | Select-Object -ExpandProperty id
                        Write-Verbose "Investigation package collection was successfully initiated for device $DeviceName - ActionID: $ActionID"
                        $ActionID
                    }
                    Else{
                        $ActionID = "0000000-0000-0000-0000-000000000000"
                        Write-Warning "Initiating investigation pacakge collection for device $DeviceName failed!"
                        Write-Error "StatusCode: $($CollectResponse.StatusCode)"
                        $ActionID
                    }
                }
                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)"
                    $ActionID = "0000000-0000-0000-0000-000000000000"
                    $ActionID
                }
            }
        }
    }
    End{
        Write-Verbose "Device: $DeviceName"
        Write-Verbose "DeviceID: $MDATPDeviceID"
        Write-Verbose "Action: Collection Investigation Package"
        Write-Verbose "Comment: $Comment"
        Write-Verbose "ActionID: $($ActionID)"
        Write-Verbose "StatusCode: $($response.statuscode)"
        Write-Verbose "StatusDescription: $($CollectResponse.StatusDescription)"
    }
}

function Start-MDATPIsolation{
    <#
    .Synopsis
    Start-MDATPIsolation
 
    .DESCRIPTION
    Start-MDATPIsolation initiates the isolation of the specified device from the network
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER IsolationType
    Type of the isolation. Allowed values are: 'Full' or 'Selective'.
 
    .PARAMETER Comment
    Comment that is added to the request, if no comment is provided the default commment 'submitted by automation' is used.
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Start-MDATPIsolation -DeviceName computer02 -IsolationType Full -Comment "incident1973"
 
    This command isolates device computer02 from the network
 
    .EXAMPLE
    Start-MDATPIsolation -DeviceName computer02 -IsolationType Selective -Comment "incident1973"
 
    This command isolates device computer02 from the network but allows communication through Outlook and Skype
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 12.04.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param(
        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # IsolationType controls the type of isolation to perform
        [Parameter(Mandatory=$true)]
        [ValidateSet('Full','Selective')]
        [String]$IsolationType,

        # Comment for the request
        [Parameter(Mandatory=$false)]
        [String]$Comment,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token
        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"
        If([string]::IsNullOrEmpty($Comment)){
            $Comment = "submitted by automation"
        }
        $DeviceName = $DeviceName.ToLower()
        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
        If ($DeviceName){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }

        If($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $MDATPDeviceID = $ActionDevice.id
            if ($pscmdlet.ShouldProcess("$DeviceName", "Start Isolation: $IsolationType")){
                Try{
                    $IsolationTypeInput = @{"IsolationType" = "$IsolationType"; "Comment"= "$Comment"} | ConvertTo-Json
                    $IsolateUri = "$MachineAPI/$MDATPDeviceID/isolate"
                    $IsolateResponse  =Invoke-WebRequest -Uri $IsolateUri -Headers $Headers -Method Post -Body $IsolationTypeInput
                    If ($IsolateResponse.StatusCode -eq 201){
                        $ActionID = $IsolateResponse.content | ConvertFrom-Json | Select-Object -ExpandProperty id
                        Write-Verbose "$IsolationType isolation was successfully initiated for device $DeviceName -ActionID: $ActionID"
                        $ActionID
                    }
                    Else{
                        $ActionID = "0000000-0000-0000-0000-000000000000"
                        Write-Warning "Initiating $IsolationType isolation for device $DeviceName failed!"
                        Write-Error "StatusCode: $($IsolateResponse.StatusCode)"
                        $ActionID
                    }
                }
                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)"
                    $ActionID = "0000000-0000-0000-0000-000000000000"
                    $ActionID
                }
            }
        }
    }
    End{
        Write-Verbose "Device: $DeviceName"
        Write-Verbose "DeviceID: $MDATPDeviceID"
        Write-Verbose "IsolationType: $IsolationType"
        Write-Verbose "Comment: $Comment"
        Write-Verbose "ActionID: $($ActionID)"
        Write-Verbose "StatusCode: $($IsolateResponse.statuscode)"
        Write-Verbose "StatusDescription: $($IsolateResponse.StatusDescription)"
    }
}

function Stop-MDATPAppRestriction{
    <#
    .Synopsis
    Stop-MDATPAppRestriction
 
    .DESCRIPTION
    Stop-MDATPAppRestriction removes app execution restrictions on the machine.
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER Comment
    Comment that is added to the request, if no comment is provided the default commment 'submitted by automation' is used.
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Stop-MDATPAppRestriction -DeviceName computer02 -Comment "incident1973"
 
    This command removes app execution restrictions from device computer02
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 12.04.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param(
        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Comment for the request
        [Parameter(Mandatory=$false)]
        [String]$Comment,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token
        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"
        If([string]::IsNullOrEmpty($Comment)){
            $Comment = "submitted by automation"
        }
        $DeviceName = $DeviceName.ToLower()
        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
        If ($DeviceName){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }

        If($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $MDATPDeviceID = $ActionDevice.id

            if ($pscmdlet.ShouldProcess("$DeviceName", "Start Isolation: $IsolationType")){
                Try{
                    $UnAppRestrictionInput = @{"Comment" = "$Comment"} | ConvertTo-Json
                    $UnAppRestrictionUri = "$MachineAPI/$MDATPDeviceID/unrestrictCodeExecution "
                    $UnAppRestrictionResponse  =Invoke-WebRequest -Uri $UnAppRestrictionUri -Headers $Headers -Method Post -Body $UnAppRestrictionInput
                    If ($UnAppRestrictionResponse.StatusCode -eq 201){
                        $ActionID = $UnAppRestrictionResponse.content | ConvertFrom-Json | Select-Object -ExpandProperty id
                        Write-Verbose "Remove App restriction was successfully initiated for device $DeviceName -ActionID: $ActionID"
                        $ActionID
                    }
                    Else{
                        $ActionID = "0000000-0000-0000-0000-000000000000"
                        Write-Warning "Initiating app restriction for device $DeviceName failed!"
                        Write-Error "StatusCode: $($UnAppRestrictionResponse.StatusCode)"
                        $ActionID
                    }
                }
                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)"
                    $ActionID = "0000000-0000-0000-0000-000000000000"
                    $ActionID
                }
            }
        }
    }
    End{
        Write-Verbose "Device: $DeviceName"
        Write-Verbose "DeviceID: $MDATPDeviceID"
        Write-Verbose "Comment: $Comment"
        Write-Verbose "ActionID: $($ActionID)"
        Write-Verbose "StatusCode: $($IsolateResponse.statuscode)"
        Write-Verbose "StatusDescription: $($IsolateResponse.StatusDescription)"
    }
}

function Stop-MDATPIsolation{
    <#
    .Synopsis
    Stop-MDATPIsolation
 
    .DESCRIPTION
    Stop-MDATPIsolation removes network isolation for the specified device
 
    .PARAMETER DeviceName
    Computername of the device
 
    .PARAMETER DeviceID
    The unique device ID of the device
 
    .PARAMETER Comment
    Comment that is added to the request, if no comment is provided the default commment 'submitted by automation' is used.
 
    .PARAMETER MTPConfigFile
    The MTPConfigFile contains the API connection information, if not specified a default PoshMTPconfig.json is used that must be located in the module folder
 
    .EXAMPLE
    Stop-MDATPIsolation -DeviceName computer02 -Comment "incident1973"
 
    This command removes network isolation for device computer02
 
    .NOTES
    Version: 1.0
    Author: Alex Verboon
    Creation Date: 12.04.2020
    Purpose/Change: Initial script development
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param(
        # Computername of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceName')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceName,

        # Unique device id of the MDATP managed device
        [Parameter(Mandatory=$true,
            ParameterSetName='DeviceID')]
        [ValidateNotNullOrEmpty()]
        [String]$DeviceID,

        # Comment for the request
        [Parameter(Mandatory=$false)]
        [String]$Comment,

        # API Configuration file
        [Parameter(Mandatory=$false)]
        [String]$MTPConfigFile
    )

    Begin{
        # Begin Get API Information
        If ($MTPConfigFile){
            $PoshMTPconfigFilePath = $MTPConfigFile
            Write-Verbose "MTP ConfigFile parameter: $PoshMTPconfigFilePath"
        }
        Else{
            # If no configfile is defined we use a defined lcoation .\Config\PoshMTPconfig.json
            $ConfigFileDir =  [IO.Directory]::GetParent($PSScriptRoot)
            $PoshMTPconfigFilePath = "$ConfigFileDir\" +  "PoshMTPconfig.json"
            Write-Verbose "MTP ConfigFile static: $PoshMTPconfigFilePath"
        }

        Write-Verbose "Checking for $PoshMTPconfigFilePath"
        If (Test-Path -Path $PoshMTPconfigFilePath -PathType Leaf){
            $ConfigSettings = @(Get-Content -Path "$PoshMTPconfigFilePath" | ConvertFrom-Json)
            $OAuthUri = $ConfigSettings.API_MDATP.OAuthUri
            $ClientID = $ConfigSettings.API_MDATP.ClientID
            $ClientSecret = $ConfigSettings.API_MDATP.ClientSecret
        }
        Else{
            Write-Error "$PoshMTPconfigFilePath not found"
            Break
        }
        # End Get API Information

        # Connect with MDATP API
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $Body = @{
            resource      = "https://api.securitycenter.windows.com"
            client_id     = $ClientID
            client_secret = $ClientSecret
            grant_type    = 'client_credentials'
            redirectUri   = "https://localhost:8000"
        }
        $Response = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body
        #$Authorization = Invoke-RestMethod -Method Post -Uri $OAuthUri -Body $Body -ContentType "application/x-www-form-urlencoded" -UseBasicParsing
        #$access_token = $Authorization.access_token
        $headers = @{
            'Content-Type' = 'application/json'
            Accept         = 'application/json'
            Authorization  = "Bearer $($Response.access_token)"
        }
    }
    Process{
        $MDATP_API_URI = "https://api.securitycenter.windows.com/api"
        If([string]::IsNullOrEmpty($Comment)){
            $Comment = "submitted by automation"
        }
        $DeviceName = $DeviceName.ToLower()

        # Get the MDATP devices
        $MachineAPI = "$MDATP_API_URI/machines"
        $Machines = @(Invoke-RestMethod -Uri "$MachineAPI" -Headers $Headers -Method Get -Verbose -ContentType application/json)
        If ($DeviceName){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.computerDnsName -like "$DeviceName"})
        }
        Elseif ($DeviceID){
            $ActionDevice = @($machines.value | Select-Object * | Where-Object {$_.id -like "$DeviceID"})
        }

        If($ActionDevice.count -gt 1){
            Write-Warning "There are multiple device records with this computername, please specify the MDATP device id"
            $ActionDevice | Select-Object computerDnsName, id
            Break
        }
        Elseif($ActionDevice.count -eq 0){
            Write-Warning "No device records found that match DeviceName $DeviceName"
            Break
        }
        Elseif($ActionDevice.count -eq 1){
            $MDATPDeviceID = $ActionDevice.id
            if ($pscmdlet.ShouldProcess("$DeviceName", "Stop Isolation")){
                Try{
                    $UnIsolationInput = @{"Comment" = "$Comment"} | ConvertTo-Json
                    $UnIsolateUri = "$MachineAPI/$MDATPDeviceID/unisolate "
                    $UnIsolateResponse  =Invoke-WebRequest -Uri $UnIsolateUri -Headers $Headers -Method Post -Body $UnIsolationInput
                    If ($UnIsolateResponse.StatusCode -eq 201){
                        $ActionID = $UnIsolateResponse.content | ConvertFrom-Json | Select-Object -ExpandProperty id
                        Write-Verbose "Remove isolation was successfully initiated for device $DeviceName -ActionID: $ActionID"
                        $ActionID
                    }
                    Else{
                        $ActionID = "0000000-0000-0000-0000-000000000000"
                        Write-Warning "Removing isolation for device $DeviceName failed!"
                        Write-Error "StatusCode: $($UnIsolateResponse.StatusCode)"
                        $ActionID
                    }
                }
                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)"
                    $ActionID = "0000000-0000-0000-0000-000000000000"
                    $ActionID
                }
            }
        }
    }
    End{
        Write-Verbose "Device: $DeviceName"
        Write-Verbose "DeviceID: $MDATPDeviceID"
        Write-Verbose "Comment: $Comment"
        Write-Verbose "ActionID: $($ActionID)"
        Write-Verbose "StatusCode: $($UnIsolateResponse.statuscode)"
        Write-Verbose "StatusDescription: $($UnIsolateResponse.StatusDescription)"
    }
}