DSCResources/MSFT_IntuneMobileThreatDefenseConnector/MSFT_IntuneMobileThreatDefenseConnector.psm1

# https://learn.microsoft.com/en-us/graph/api/resources/intune-onboarding-mobilethreatdefenseconnector?view=graph-rest-1.0
# https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.devicemanagement.administration/new-mgdevicemanagementmobilethreatdefenseconnector?view=graph-powershell-1.0

function Get-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        #region Intune parameters

        [Parameter(Mandatory = $true)]
        [System.String]
        $Id,

        [Parameter()]
        [System.String]
        $DisplayName,

        [Parameter()]
        [System.Boolean]
        $AllowPartnerToCollectIosApplicationMetadata,

        [Parameter()]
        [System.Boolean]
        $AllowPartnerToCollectIosPersonalApplicationMetadata,

        [Parameter()]
        [System.Boolean]
        $AndroidDeviceBlockedOnMissingPartnerData,

        [Parameter()]
        [System.Boolean]
        $AndroidEnabled,

        [Parameter()]
        [System.Boolean]
        $AndroidMobileApplicationManagementEnabled,

        [Parameter()]
        [System.Boolean]
        $IosDeviceBlockedOnMissingPartnerData,

        [Parameter()]
        [System.Boolean]
        $IosEnabled,

        [Parameter()]
        [System.Boolean]
        $IosMobileApplicationManagementEnabled,

        [Parameter()]
        [System.DateTime]
        $LastHeartbeatDateTime,

        [Parameter()]
        [System.Boolean]
        $MicrosoftDefenderForEndpointAttachEnabled,

        [Parameter()]
        [System.String]
        $PartnerState,

        [Parameter()]
        [System.Int32]
        $PartnerUnresponsivenessThresholdInDays,

        [Parameter()]
        [System.Boolean]
        $PartnerUnsupportedOSVersionBlocked,

        [Parameter()]
        [System.Boolean]
        $WindowsDeviceBlockedOnMissingPartnerData,

        [Parameter()]
        [System.Boolean]
        $WindowsEnabled,

        #endregion Intune parameters

        [Parameter()]
        [ValidateSet('Present', 'Absent')]
        [System.String]
        $Ensure = 'Present',

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $Credential,

        [Parameter()]
        [System.String]
        $ApplicationId,

        [Parameter()]
        [System.String]
        $TenantId,

        [Parameter()]
        [System.String]
        $CertificateThumbprint,

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $ApplicationSecret,

        [Parameter()]
        [Switch]
        $ManagedIdentity,

        [Parameter()]
        [System.String[]]
        $AccessTokens
    )

    New-M365DSCConnection -Workload 'MicrosoftGraph' `
        -InboundParameters $PSBoundParameters | Out-Null

    #Ensure the proper dependencies are installed in the current environment.
    Confirm-M365DSCDependencies

    #region Telemetry
    $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '')
    $CommandName = $MyInvocation.MyCommand
    $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName `
        -CommandName $CommandName `
        -Parameters $PSBoundParameters
    Add-M365DSCTelemetryEvent -Data $data
    #endregion

    $nullResult = $PSBoundParameters
    $nullResult.Ensure = 'Absent'
    try
    {
        if ($null -ne $Script:exportedInstances -and $Script:ExportMode)
        {
            $instance = $Script:exportedInstances | Where-Object -FilterScript { $_.Id -eq $Id }
        }
        else
        {
            $instance = Get-MgBetaDeviceManagementMobileThreatDefenseConnector -MobileThreatDefenseConnectorId $Id -ErrorAction SilentlyContinue
        }

        if ($null -eq $instance)
        {
            Write-Verbose -Message "Could not find MobileThreatDefenseConnector by Id: {$Id}."
            if (-Not [string]::IsNullOrEmpty($DisplayName))
            {
                # There is no API which searches MobileThreatDefenseConnector by its DisplayName so the below code is commented out.
                # $instance = Get-MgBetaDeviceManagementMobileThreatDefenseConnector `
                # -Filter "DisplayName eq '$DisplayName'" `

                # The DisplayName property is not supported by the any API of this resource, hence hard-coded in below function for convenience.
                $connectorId = (Get-MobileThreatDefenseConnectorIdOrDisplayName -DisplayName $DisplayName).Id
                $instance = Get-MgBetaDeviceManagementMobileThreatDefenseConnector `
                    -MobileThreatDefenseConnectorId $connectorId
                -ErrorAction SilentlyContinue
            }

            if ($null -eq $instance)
            {
                Write-Verbose -Message "Could not find MobileThreatDefenseConnector by DisplayName: {$DisplayName}."
                return $nullResult
            }
        }

        if ([string]::IsNullOrEmpty($DisplayName))
        {
            $DisplayName = (Get-MobileThreatDefenseConnectorIdOrDisplayName -Id $instance.Id).DisplayName
        }

        $results = @{
            Id                                                  = $instance.Id
            DisplayName                                         = $DisplayName
            ResponseHeadersVariable                             = $instance.ResponseHeadersVariable
            AllowPartnerToCollectIosApplicationMetadata         = $instance.AllowPartnerToCollectIosApplicationMetadata
            AllowPartnerToCollectIosPersonalApplicationMetadata = $instance.AllowPartnerToCollectIosPersonalApplicationMetadata
            AndroidDeviceBlockedOnMissingPartnerData            = $instance.AndroidDeviceBlockedOnMissingPartnerData
            AndroidEnabled                                      = $instance.AndroidEnabled
            AndroidMobileApplicationManagementEnabled           = $instance.AndroidMobileApplicationManagementEnabled
            IosDeviceBlockedOnMissingPartnerData                = $instance.IosDeviceBlockedOnMissingPartnerData
            IosEnabled                                          = $instance.IosEnabled
            IosMobileApplicationManagementEnabled               = $instance.IosMobileApplicationManagementEnabled
            LastHeartbeatDateTime                               = $instance.LastHeartbeatDateTime
            MicrosoftDefenderForEndpointAttachEnabled           = $instance.MicrosoftDefenderForEndpointAttachEnabled
            PartnerState                                        = $instance.PartnerState.ToString()
            PartnerUnresponsivenessThresholdInDays              = $instance.PartnerUnresponsivenessThresholdInDays
            PartnerUnsupportedOSVersionBlocked                  = $instance.PartnerUnsupportedOSVersionBlocked
            WindowsDeviceBlockedOnMissingPartnerData            = $instance.WindowsDeviceBlockedOnMissingPartnerData
            WindowsEnabled                                      = $instance.WindowsEnabled

            Ensure                                              = 'Present'
            Credential                                          = $Credential
            ApplicationId                                       = $ApplicationId
            TenantId                                            = $TenantId
            CertificateThumbprint                               = $CertificateThumbprint
            ApplicationSecret                                   = $ApplicationSecret
            ManagedIdentity                                     = $ManagedIdentity.IsPresent
            AccessTokens                                        = $AccessTokens
        }

        return [System.Collections.Hashtable] $results
    }
    catch
    {
        Write-Verbose -Message $_
        New-M365DSCLogEntry -Message 'Error retrieving data:' `
            -Exception $_ `
            -Source $($MyInvocation.MyCommand.Source) `
            -TenantId $TenantId `
            -Credential $Credential

        return $nullResult
    }
}

function Set-TargetResource
{
    [CmdletBinding()]
    param
    (
        #region Intune parameters

        [Parameter(Mandatory = $true)]
        [System.String]
        $Id,

        [Parameter()]
        [System.String]
        $DisplayName,

        [Parameter()]
        [System.Boolean]
        $AllowPartnerToCollectIosApplicationMetadata,

        [Parameter()]
        [System.Boolean]
        $AllowPartnerToCollectIosPersonalApplicationMetadata,

        [Parameter()]
        [System.Boolean]
        $AndroidDeviceBlockedOnMissingPartnerData,

        [Parameter()]
        [System.Boolean]
        $AndroidEnabled,

        [Parameter()]
        [System.Boolean]
        $AndroidMobileApplicationManagementEnabled,

        [Parameter()]
        [System.Boolean]
        $IosDeviceBlockedOnMissingPartnerData,

        [Parameter()]
        [System.Boolean]
        $IosEnabled,

        [Parameter()]
        [System.Boolean]
        $IosMobileApplicationManagementEnabled,

        [Parameter()]
        [System.DateTime]
        $LastHeartbeatDateTime,

        [Parameter()]
        [System.Boolean]
        $MicrosoftDefenderForEndpointAttachEnabled,

        [Parameter()]
        [System.String]
        $PartnerState,

        [Parameter()]
        [System.Int32]
        $PartnerUnresponsivenessThresholdInDays,

        [Parameter()]
        [System.Boolean]
        $PartnerUnsupportedOSVersionBlocked,

        [Parameter()]
        [System.Boolean]
        $WindowsDeviceBlockedOnMissingPartnerData,

        [Parameter()]
        [System.Boolean]
        $WindowsEnabled,

        #endregion Intune parameters

        [Parameter()]
        [ValidateSet('Present', 'Absent')]
        [System.String]
        $Ensure = 'Present',

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $Credential,

        [Parameter()]
        [System.String]
        $ApplicationId,

        [Parameter()]
        [System.String]
        $TenantId,

        [Parameter()]
        [System.String]
        $CertificateThumbprint,

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $ApplicationSecret,

        [Parameter()]
        [Switch]
        $ManagedIdentity,

        [Parameter()]
        [System.String[]]
        $AccessTokens
    )

    #Ensure the proper dependencies are installed in the current environment.
    Confirm-M365DSCDependencies

    #region Telemetry
    $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '')
    $CommandName = $MyInvocation.MyCommand
    $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName `
        -CommandName $CommandName `
        -Parameters $PSBoundParameters
    Add-M365DSCTelemetryEvent -Data $data
    #endregion

    $currentInstance = Get-TargetResource @PSBoundParameters
    $SetParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters

    # Remove the DisplayName parameter as the Graph API does not support it
    $SetParameters.Remove('DisplayName') | Out-Null
    $SetParameters.Remove('Id') | Out-Null
    $SetParameters.Remove('LastHeartbeatDateTime') | Out-Null

    # CREATE
    if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent')
    {
        New-MgBetaDeviceManagementMobileThreatDefenseConnector @SetParameters
    }
    # UPDATE
    elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present')
    {
        Update-MgBetaDeviceManagementMobileThreatDefenseConnector -MobileThreatDefenseConnectorId $currentInstance.Id @SetParameters
    }
    # REMOVE
    elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present')
    {
        Remove-MgBetaDeviceManagementMobileThreatDefenseConnector -MobileThreatDefenseConnectorId $currentInstance.Id -Confirm:$false
    }
}

function Test-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        #region Intune parameters

        [Parameter(Mandatory = $true)]
        [System.String]
        $Id,

        [Parameter()]
        [System.String]
        $DisplayName,

        [Parameter()]
        [System.Boolean]
        $AllowPartnerToCollectIosApplicationMetadata,

        [Parameter()]
        [System.Boolean]
        $AllowPartnerToCollectIosPersonalApplicationMetadata,

        [Parameter()]
        [System.Boolean]
        $AndroidDeviceBlockedOnMissingPartnerData,

        [Parameter()]
        [System.Boolean]
        $AndroidEnabled,

        [Parameter()]
        [System.Boolean]
        $AndroidMobileApplicationManagementEnabled,

        [Parameter()]
        [System.Boolean]
        $IosDeviceBlockedOnMissingPartnerData,

        [Parameter()]
        [System.Boolean]
        $IosEnabled,

        [Parameter()]
        [System.Boolean]
        $IosMobileApplicationManagementEnabled,

        [Parameter()]
        [System.DateTime]
        $LastHeartbeatDateTime,

        [Parameter()]
        [System.Boolean]
        $MicrosoftDefenderForEndpointAttachEnabled,

        [Parameter()]
        [System.String]
        [ValidateSet('unavailable', 'available', 'enabled', 'unresponsive', 'notSetUp', 'error')]
        $PartnerState,

        [Parameter()]
        [System.Int32]
        $PartnerUnresponsivenessThresholdInDays,

        [Parameter()]
        [System.Boolean]
        $PartnerUnsupportedOSVersionBlocked,

        [Parameter()]
        [System.Boolean]
        $WindowsDeviceBlockedOnMissingPartnerData,

        [Parameter()]
        [System.Boolean]
        $WindowsEnabled,

        #endregion Intune parameters

        [Parameter()]
        [ValidateSet('Present', 'Absent')]
        [System.String]
        $Ensure = 'Present',

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $Credential,

        [Parameter()]
        [System.String]
        $ApplicationId,

        [Parameter()]
        [System.String]
        $TenantId,

        [Parameter()]
        [System.String]
        $CertificateThumbprint,

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $ApplicationSecret,

        [Parameter()]
        [Switch]
        $ManagedIdentity,

        [Parameter()]
        [System.String[]]
        $AccessTokens
    )

    #Ensure the proper dependencies are installed in the current environment.
    Confirm-M365DSCDependencies

    #region Telemetry
    $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '')
    $CommandName = $MyInvocation.MyCommand
    $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName `
        -CommandName $CommandName `
        -Parameters $PSBoundParameters
    Add-M365DSCTelemetryEvent -Data $data
    #endregion

    $CurrentValues = Get-TargetResource @PSBoundParameters
    $ValuesToCheck = ([Hashtable]$PSBoundParameters).Clone()
    $ValuesToCheck.Remove('LastHeartbeatDateTime') | Out-Null

    Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)"
    Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)"

    $testResult = Test-M365DSCParameterState -CurrentValues $CurrentValues `
        -Source $($MyInvocation.MyCommand.Source) `
        -DesiredValues $PSBoundParameters `
        -ValuesToCheck $ValuesToCheck.Keys

    Write-Verbose -Message "Test-TargetResource returned $testResult"

    return $testResult
}

function Export-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.String])]
    param
    (
        [Parameter()]
        [System.Management.Automation.PSCredential]
        $Credential,

        [Parameter()]
        [System.String]
        $ApplicationId,

        [Parameter()]
        [System.String]
        $TenantId,

        [Parameter()]
        [System.String]
        $CertificateThumbprint,

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $ApplicationSecret,

        [Parameter()]
        [Switch]
        $ManagedIdentity,

        [Parameter()]
        [System.String[]]
        $AccessTokens
    )

    $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' `
        -InboundParameters $PSBoundParameters

    #Ensure the proper dependencies are installed in the current environment.
    Confirm-M365DSCDependencies

    #region Telemetry
    $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '')
    $CommandName = $MyInvocation.MyCommand
    $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName `
        -CommandName $CommandName `
        -Parameters $PSBoundParameters
    Add-M365DSCTelemetryEvent -Data $data
    #endregion

    try
    {
        $Script:ExportMode = $true
        [array] $Script:exportedInstances = Get-MgBetaDeviceManagementMobileThreatDefenseConnector -ErrorAction Stop

        $i = 1
        $dscContent = ''
        if ($Script:exportedInstances.Length -eq 0)
        {
            Write-Host $Global:M365DSCEmojiGreenCheckMark
        }
        else
        {
            Write-Host "`r`n" -NoNewline
        }

        foreach ($config in $Script:exportedInstances)
        {
            $displayedKey = $config.Id
            Write-Host " |---[$i/$($Script:exportedInstances.Count)] $displayedKey" -NoNewline
            $params = @{
                Id                                                  = $config.Id
                DisplayName                                         = $config.DisplayName
                AllowPartnerToCollectIosApplicationMetadata         = $config.AllowPartnerToCollectIosApplicationMetadata
                AllowPartnerToCollectIosPersonalApplicationMetadata = $config.AllowPartnerToCollectIosPersonalApplicationMetadata
                AndroidDeviceBlockedOnMissingPartnerData            = $config.AndroidDeviceBlockedOnMissingPartnerData
                AndroidEnabled                                      = $config.AndroidEnabled
                AndroidMobileApplicationManagementEnabled           = $config.AndroidMobileApplicationManagementEnabled
                IosDeviceBlockedOnMissingPartnerData                = $config.IosDeviceBlockedOnMissingPartnerData
                IosEnabled                                          = $config.IosEnabled
                IosMobileApplicationManagementEnabled               = $config.IosMobileApplicationManagementEnabled
                LastHeartbeatDateTime                               = $config.LastHeartbeatDateTime
                MicrosoftDefenderForEndpointAttachEnabled           = $config.MicrosoftDefenderForEndpointAttachEnabled
                PartnerState                                        = $config.PartnerState.ToString()
                PartnerUnresponsivenessThresholdInDays              = $config.PartnerUnresponsivenessThresholdInDays
                PartnerUnsupportedOSVersionBlocked                  = $config.PartnerUnsupportedOSVersionBlocked
                WindowsDeviceBlockedOnMissingPartnerData            = $config.WindowsDeviceBlockedOnMissingPartnerData
                WindowsEnabled                                      = $config.WindowsEnabled

                Ensure                                              = 'Present'
                Credential                                          = $Credential
                ApplicationId                                       = $ApplicationId
                TenantId                                            = $TenantId
                CertificateThumbprint                               = $CertificateThumbprint
                ApplicationSecret                                   = $ApplicationSecret
                ManagedIdentity                                     = $ManagedIdentity.IsPresent
                AccessTokens                                        = $AccessTokens
            }

            $Results = Get-TargetResource @Params
            $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode `
                -Results $Results

            $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName `
                -ConnectionMode $ConnectionMode `
                -ModulePath $PSScriptRoot `
                -Results $Results `
                -Credential $Credential
            $dscContent += $currentDSCBlock
            Save-M365DSCPartialExport -Content $currentDSCBlock `
                -FileName $Global:PartialExportFileName
            $i++
            Write-Host $Global:M365DSCEmojiGreenCheckMark
        }
        return $dscContent
    }
    catch
    {
        Write-Host $Global:M365DSCEmojiRedX

        New-M365DSCLogEntry -Message 'Error during Export:' `
            -Exception $_ `
            -Source $($MyInvocation.MyCommand.Source) `
            -TenantId $TenantId `
            -Credential $Credential

        return ''
    }
}

#region Helper functions

function Get-MobileThreatDefenseConnectorIdOrDisplayName
{
    param (
        [Parameter(Mandatory = $false)]
        [string]$Id,

        [Parameter(Mandatory = $false)]
        [string]$DisplayName
    )

    # Hashtable mapping IDs to Display Names
    $IdToDisplayNameMap = @{
        'fc780465-2017-40d4-a0c5-307022471b92' = 'Microsoft Defender for Endpoint'
        '860d3ab4-8fd1-45f5-89cd-ecf51e4f92e5' = 'BETTER Mobile Security'
        'd3ddeae8-441f-4681-b80f-aef644f7195a' = 'Check Point Harmony Mobile'
        '8d0ed095-8191-4bd3-8a41-953b22d51ff7' = 'Pradeo'
        '1f58d6d2-02cc-4c80-b008-1bfe7396a10a' = 'Jamf Trust'
        '4873197-ffec-4dfc-9816-db65f34c7cb9'  = 'Trellix Mobile Security'
        'a447eca6-a986-4d3f-9838-5862bf50776c' = 'CylancePROTECT Mobile'
        '4928f0f6-2660-4f69-b4c5-5170ec921f7b' = 'Trend Micro'
        'bb13fe25-ce1f-45aa-b278-cabbc6b9072e' = 'SentinelOne'
        'e6f777f8-e4c2-4a5b-be01-50b5c124bc7f' = 'Windows Security Center'
        '29ee2d98-e795-475f-a0f8-0802dc3384a9' = 'CrowdStrike Falcon for Mobile'
        '870b252b-0ef0-4707-8847-50fc571472b3' = 'Sophos'
        '2c7790de-8b02-4814-85cf-e0c59380dee8' = 'Lookout for Work'
        '28fd67fd-b179-4629-a8b0-dad420b697c7' = 'Symantec Endpoint Protection'
        '08a8455c-48dd-45ff-ad82-7211355354f3' = 'Zimperium'
    }

    # If Id is provided, look up the DisplayName
    if ($null -ne $Id)
    {
        $displayName = $IdToDisplayNameMap[$Id]
    }

    # If DisplayName is provided, look up the Id
    # Create a reverse lookup hashtable for DisplayName to Id
    $DisplayNameToIdMap = @{}
    foreach ($key in $IdToDisplayNameMap.Keys)
    {
        $DisplayNameToIdMap[$IdToDisplayNameMap[$key]] = $key
    }
    if (-not [string]::IsNullOrEmpty($DisplayName))
    {
        $Id = $DisplayNameToIdMap[$DisplayName]
        if (-not $Id)
        {
            Write-Host "Internal func: DisplayName '$DisplayName' not found."
            return
        }
    }

    # Create the results tuple
    return @{
        Id          = $Id
        DisplayName = $displayName
    }
}

Export-ModuleMember -Function *-TargetResource