Public/Import-AzSentinelDataConnector.ps1

#requires -module @{ModuleName = 'Az.Accounts'; ModuleVersion = '1.5.2'}
#requires -version 6.2

function Import-AzSentinelDataConnector {
    <#
    .SYNOPSIS
    Import Azure Sentinel Data Connectors
    .DESCRIPTION
    This function imports Azure Sentinel Data Connectors
    .PARAMETER SubscriptionId
    Enter the subscription ID, if no subscription ID is provided then current AZContext subscription will be used
    .PARAMETER WorkspaceName
    Enter the Workspace name
    .PARAMETER SettingsFile
    Path to the JSON file for the Data Connectors
    .EXAMPLE
    Import-AzSentinelDataConnector -WorkspaceName "" -SettingsFile ".\examples\DataConnectors.json"
    In this example all the Data Conenctors configured in the JSON file will be created or updated
    #>


    param (
        [Parameter(Mandatory = $false,
            ParameterSetName = "Sub")]
        [ValidateNotNullOrEmpty()]
        [string] $SubscriptionId,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string] $WorkspaceName,

        [Parameter(Mandatory, ValueFromPipeline)]
        [ValidateScript( { (Test-Path -Path $_) -and ($_.Extension -in '.json') })]
        [System.IO.FileInfo] $SettingsFile
    )

    begin {
        precheck
    }

    process {
        switch ($PsCmdlet.ParameterSetName) {
            Sub {
                $arguments = @{
                    WorkspaceName  = $WorkspaceName
                    SubscriptionId = $SubscriptionId
                }
            }
            default {
                $arguments = @{
                    WorkspaceName  = $WorkspaceName
                    SubscriptionId = $script:SubscriptionId
                }
            }
        }

        try {
            Get-LogAnalyticWorkspace @arguments -ErrorAction Stop
        }
        catch {
            Write-Error $_.Exception.Message
            break
        }

        if ($SettingsFile.Extension -eq '.json') {
            try {
                $connectors = Get-Content -Raw $SettingsFile | ConvertFrom-Json -Depth 99
            }
            catch {
                Write-Verbose $_
                Write-Error -Message 'Unable to import JSON file' -ErrorAction Stop
            }
        }
        else {
            Write-Error -Message 'Unsupported extension for SettingsFile' -ErrorAction Stop
        }

        <#
            Get all the DataConenctors
        #>

        $enabledDataConnectors = Get-AzSentinelDataConnector @arguments -ErrorAction SilentlyContinue

        <#
            Get AzureActivityLog connector data
        #>

        $azureActivityLog = Get-AzSentinelDataConnector @arguments -DataSourceName 'AzureActivityLog' -ErrorAction SilentlyContinue

        foreach ($item in $connectors.AzureActivityLog) {
            if ($null -ne $azureActivityLog){
                $azureActivity = $azureActivityLog | Where-Object { $_.properties.linkedResourceId.Split('/')[2] -eq $item.subscriptionId }
            }
            else {
                $azureActivity
            }

            if ($azureActivity) {
                Write-Host "AzureActivityLog is already enabled on '$($item.subscriptionId)'"
            }
            else {
                $name = ($item.subscriptionId).Replace('-', '')
                $connectorBody = @{
                    id         = "$script:Workspace/datasources/$name"
                    name       = $name
                    type       = 'Microsoft.OperationalInsights/workspaces/datasources'
                    kind       = 'AzureActivityLog'
                    properties = @{
                        linkedResourceId = "/subscriptions/$($item.subscriptionId)/providers/microsoft.insights/eventtypes/management"
                    }
                }

                $uri = "$baseUri/datasources/$($name)?api-version=2020-03-01-preview"

                try {
                    $result = Invoke-webrequest -Uri $uri -Method Put -Headers $script:authHeader -Body ($connectorBody | ConvertTo-Json -Depth 4 -EnumsAsStrings)

                    Write-Host "Successfully enabled AzureActivityLog for: $($item.subscriptionId) with status: $($result.StatusDescription)"
                }
                catch {
                    $errorReturn = $_.Exception.Message
                    Write-Verbose $_
                    Write-Error "Unable to invoke webrequest with error message: $($errorReturn)" -ErrorAction Stop
                }
            }
        }

        #AzureSecurityCenter connector
        foreach ($item in $connectors.AzureSecurityCenter) {
            if ($null -ne $enabledDataConnectors){
                $azureSecurityCenter = $enabledDataConnectors | Where-Object { $_.Kind -eq "AzureSecurityCenter" -and $_.properties.subscriptionId -eq $item.subscriptionId }
            }
            else {
                $azureSecurityCenter
            }
            $skip = $false

            if ($null -ne $azureSecurityCenter) {
                if ($azureSecurityCenter.properties.dataTypes.alerts.state -eq $item.state) {
                    Write-Host "AzureSecurityCenter is already '$($item.state)' for subscription '$($azureSecurityCenter.properties.subscriptionId)'"
                    $skip = $true
                }
                else {
                    $connectorBody = @{
                        id         = $azureSecurityCenter.id
                        name       = $azureSecurityCenter.name
                        etag       = $azureSecurityCenter.etag
                        type       = 'Microsoft.SecurityInsights/dataConnectors'
                        kind       = 'AzureSecurityCenter'
                        properties = @{
                            subscriptionId = $azureSecurityCenter.properties.subscriptionId
                            dataTypes      = @{
                                alerts = @{
                                    state = $item.state
                                }
                            }
                        }
                    }
                }
            }
            else {
                $guid = (New-Guid).Guid

                $connectorBody = @{
                    id         = "$script:Workspace/providers/Microsoft.SecurityInsights/dataConnectors/$guid"
                    name       = $guid
                    type       = 'Microsoft.SecurityInsights/dataConnectors'
                    kind       = 'AzureSecurityCenter'
                    properties = @{
                        subscriptionId = $item.subscriptionId
                        dataTypes      = @{
                            alerts = @{
                                state = $item.state
                            }
                        }
                    }
                }
            }

            if ($skip -eq $false) {
                # Enable or update AzureSecurityCenter with http put method
                $uri = "$script:baseUri/providers/Microsoft.SecurityInsights/dataConnectors/$($connectorBody.name)?api-version=2020-01-01"

                try {
                    $result = Invoke-webrequest -Uri $uri -Method Put -Headers $script:authHeader -Body ($connectorBody | ConvertTo-Json -Depth 4 -EnumsAsStrings)

                    Write-Host "Successfully enabled AzureSecurityCenter for: $($item.subscriptionId) with status: $($result.StatusDescription)"

                }
                catch {
                    $errorReturn = $_
                    $errorResult = ($errorReturn | ConvertFrom-Json ).error
                    Write-Verbose $_
                    Write-Error "Unable to invoke webrequest with error message: $($errorResult.message)" -ErrorAction Stop
                }
            }
        }

        # Office365 connector
        foreach ($item in $connectors.Office365) {
            if (-Not (Get-Member -InputObject $item -Name "tenantId" -MemberType Properties)) {
                Write-Error "TenantId missing"
                break
            }

            if ($null -ne $enabledDataConnectors){
                $office365 = $enabledDataConnectors | Where-Object { $_.kind -eq "Office365" -and $_.properties.tenantId -eq $item.tenantId }
            }
            else {
                $office365
            }
            $skip = $false

            if ($null -ne $office365) {
                if ($office365) {
                    Write-Host "Office365 is already enabled on tenant '$($office365.properties.tenantId)'"
                    $skip = $true
                }
                else {
                    $connectorBody = @{
                        id         = $office365.id
                        name       = $office365.name
                        etag       = $office365.etag
                        type       = 'Microsoft.SecurityInsights/dataConnectors'
                        kind       = 'Office365'
                        properties = @{
                            tenantId = $item.tenantId
                            dataTypes = @{
                                exchange = @{
                                    state = $item.exchange_state
                                }
                                sharepoint = @{
                                    state = $item.sharepoint_state
                                }
                                teams = @{
                                    state = $item.teams_state
                                }
                            }
                        }
                    }
                }
            }
            else {
                $guid = (New-Guid).Guid

                $connectorBody = @{
                    id         = "$script:Workspace/providers/Microsoft.SecurityInsights/dataConnectors/$guid"
                    name       = $guid
                    type       = 'Microsoft.SecurityInsights/dataConnectors'
                    kind       = 'Office365'
                    properties = @{
                        tenantId = $item.tenantId
                        dataTypes = @{
                            exchange = @{
                                state = $item.exchange_state
                            }
                            sharepoint = @{
                                state = $item.sharepoint_state
                            }
                            teams = @{
                                state = $item.teams_state
                            }
                        }
                    }
                }
            }

            if ($skip -eq $false) {
                # Enable or update Office365 with http put method
                $uri = "$script:baseUri/providers/Microsoft.SecurityInsights/dataConnectors/$($connectorBody.name)?api-version=2020-01-01"

                try {
                    $result = Invoke-webrequest -Uri $uri -Method Put -Headers $script:authHeader -Body ($connectorBody | ConvertTo-Json -Depth 4 -EnumsAsStrings)

                    Write-Host "Successfully enabled Office365 with status: $($result.StatusDescription) for tenant '$($item.tenantId)'"

                }
                catch {
                    $errorReturn = $_
                    $errorResult = ($errorReturn | ConvertFrom-Json ).error
                    Write-Verbose $_
                    Write-Error "Unable to invoke webrequest with error message: $($errorResult.message)" -ErrorAction Stop
                }
            }
        }

        #ThreatIntelligenceTaxii
        foreach ($item in $connectors.ThreatIntelligenceTaxii) {
            if ($enabledDataConnectors){
                $threatIntelligenceTaxii = $enabledDataConnectors | Where-Object { $_.Kind -eq "ThreatIntelligenceTaxii" -and $_.properties.friendlyName -eq $item.friendlyName }
            }
            else {
                $threatIntelligenceTaxii
            }
            $skip = $false

            if ($null -ne $threatIntelligenceTaxii) {

                if ($threatIntelligenceTaxii.properties.dataTypes.taxiiClient.state -eq $item.state) {
                    Write-Host "ThreatIntelligenceTaxii is already $($item.state) for '$($item.friendlyName)'"
                    $skip = $true
                }
                else {
                    # Compose body for connector update scenario
                    $connectorBody = @{
                        id         = $threatIntelligenceTaxii.id
                        name       = $threatIntelligenceTaxii.name
                        etag       = $threatIntelligenceTaxii.etag
                        type       = 'Microsoft.SecurityInsights/dataConnectors'
                        kind       = 'ThreatIntelligenceTaxii'
                        properties = @{
                            tenantId     = $script:tenantId
                            workspaceId  = $script:workspaceId
                            friendlyName = $item.friendlyName
                            taxiiServer  = $item.taxiiServer
                            collectionId = $item.collectionId
                            username     = $item.username
                            password     = $item.password
                            taxiiClients = $null
                            dataTypes    = @{
                                taxiiClient = @{
                                    state = $item.state
                                }
                            }
                        }
                    }
                }
            }
            else {
                $guid = (New-Guid).Guid
                # Compose body for connector enable scenario
                $connectorBody = @{
                    id         = "$script:Workspace/providers/Microsoft.SecurityInsights/dataConnectors/$guid"
                    name       = $guid
                    type       = 'Microsoft.SecurityInsights/dataConnectors'
                    kind       = 'ThreatIntelligenceTaxii'
                    properties = @{
                        tenantId     = $script:tenantId
                        workspaceId  = $script:workspaceId
                        friendlyName = $item.friendlyName
                        taxiiServer  = $item.taxiiServer
                        collectionId = $item.collectionId
                        username     = $item.username
                        password     = $item.password
                        taxiiClients = $null
                        dataTypes    = @{
                            taxiiClient = @{
                                state = $item.state
                            }
                        }
                    }
                }
            }

            if ($skip -eq $false) {
                # Enable or update ThreatIntelligenceTaxii
                $uri = "$script:baseUri/providers/Microsoft.SecurityInsights/dataConnectors/$($connectorBody.name)?api-version=2020-01-01"

                try {
                    $result = Invoke-webrequest -Uri $uri -Method Put -Headers $script:authHeader -Body ($connectorBody | ConvertTo-Json -Depth 4 -EnumsAsStrings)

                    Write-Host "Successfully enabled ThreatIntelligenceTaxii for: $($item.friendlyName) with status: $($result.StatusDescription)"
                }
                catch {
                    $errorReturn = $_.Exception.Message
                    Write-Verbose $_
                    Write-Error "Unable to invoke webrequest with error message: $($errorReturn)" -ErrorAction Stop
                }
            }
        }
    }
}