DSCResources/MSFT_WindowsDefender/MSFT_WindowsDefender.psm1

<#
    .SYNOPSIS Get state of the resource
    .EXAMPLE
        Get-TargetResource -IsSingleInstance Yes
#>

function Get-TargetResource
{
    [CmdletBinding()]    
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("Yes")]
        [System.String[]]
        $IsSingleInstance
    )
    
    if (!(PlatformSupported))
    {
        Throw  "This OS version is not supported. Windows Defender DSC supports Windows 10/Windows Server 2016 and higher versions"
    }

    $Preferences = Get-MpPreference

    $ExcludeName = 'PSComputerName','ComputerID'
    $PreferenceNames = $Preferences | Get-Member -MemberType Property | ? {$_.Name -notin $ExcludeName} | % Name

    #Initialize Hashtable
    $ReturnHash = @()

    foreach ($PreferenceName in $PreferenceNames)
    {
        $value = switch ($PreferenceName) 
                {
                    'RealTimeScanDirection' 
                         {Convert-Text -Val $Preferences.$PreferenceName -Type 'ScanDirection'}
                    {$_ -in 'RemediationScheduleDay','ScanScheduleDay','SignatureScheduleDay'} 
                         {Convert-Text -Val $Preferences.$PreferenceName -Type 'ScheduleDay'}
                    'ScanParameters' 
                         {Convert-Text -Val $Preferences.$PreferenceName -Type 'ScanParameters'}
                    'MAPSReporting'
                         {Convert-Text -Val $Preferences.$PreferenceName -Type 'MAPSReporting'}
                    'SubmitSamplesConsent'
                         {Convert-Text -Val $Preferences.$PreferenceName -Type 'SubmitSamplesConsent'}
                    {$_ -in 'ThreatIDDefaultAction_Actions','UnknownThreatDefaultAction','LowThreatDefaultAction','ModerateThreatDefaultAction','HighThreatDefaultAction','SevereThreatDefaultAction'} 
                         {Convert-Text -Val $Preferences.$PreferenceName -Type 'ThreatAction'}
                    Default
                         {$Preferences.$PreferenceName}
                }
       $ReturnHash += @{$PreferenceName = $value}
    }
 
    $ReturnHash
}

<#
    .SYNOPSIS Set state of the resource
    .EXAMPLE
        Set-TargetResource -IsSingleInstance yes -DisableRealtimeMonitoring $false
#>

function Set-TargetResource
{
    [CmdletBinding(SupportsShouldProcess=$true)]
    param
    (
        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("Yes")]
        [System.String[]]
        $IsSingleInstance,

        [System.String[]]
        $ExclusionPath,

        [System.String[]]
        $ExclusionExtension,

        [System.String[]]
        $ExclusionProcess,

        [ValidateSet("Both","Incoming","Outcoming")]
        [System.String]
        $RealTimeScanDirection,

        [System.UInt32]
        $QuarantinePurgeItemsAfterDelay,

        [ValidateSet("Everyday","Never","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday")]
        [System.String]
        $RemediationScheduleDay,

        [System.DateTime]
        $RemediationScheduleTime,

        [System.UInt32]
        $ReportingAdditionalActionTimeOut,

        [System.UInt32]
        $ReportingNonCriticalTimeOut,

        [System.UInt32]
        $ReportingCriticalFailureTimeOut,

        [System.UInt32]
        $ScanAvgCPULoadFactor,

        [System.Boolean]
        $CheckForSignaturesBeforeRunningScan,

        [System.UInt32]
        $ScanPurgeItemsAfterDelay,

        [System.Boolean]
        $ScanOnlyIfIdleEnabled,

        [ValidateSet("FullSCan","QuickScan")]
        [System.String]
        $ScanParameters,

        [ValidateSet("Everyday","Never","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday")]
        [System.String]
        $ScanScheduleDay,

        [System.DateTime]
        $ScanScheduleQuickScanTime,

        [System.DateTime]
        $ScanScheduleTime,

        [System.UInt32]
        $SignatureFirstAuGracePeriod,

        [System.UInt32]
        $SignatureAuGracePeriod,

        [System.String]
        $SignatureDefinitionUpdateFileSharesSources,

        [System.Boolean]
        $SignatureDisableUpdateOnStartupWithoutEngine,

        [System.String]
        $SignatureFallbackOrder,

        [ValidateSet("Everyday","Never","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday")]
        [System.String]
        $SignatureScheduleDay,

        [System.DateTime]
        $SignatureScheduleTime,

        [System.UInt32]
        $SignatureUpdateCatchupInterval,

        [System.UInt32]
        $SignatureUpdateInterval,

        [ValidateSet("Advanced","Basic","Disabled")]
        [System.String]
        $MAPSReporting,

        [System.Boolean]
        $DisablePrivacyMode,

        [System.Boolean]
        $RandomizeScheduleTaskTimes,

        [System.Boolean]
        $DisableBehaviorMonitoring,

        [System.Boolean]
        $DisableIntrusionPreventionSystem,

        [System.Boolean]
        $DisableIOAVProtection,

        [System.Boolean]
        $DisableRealtimeMonitoring,

        [System.Boolean]
        $DisableScriptScanning,

        [System.Boolean]
        $DisableArchiveScanning,

        [System.Boolean]
        $DisableAutoExclusions,

        [System.Boolean]
        $DisableCatchupFullScan,

        [System.Boolean]
        $DisableCatchupQuickScan,

        [System.Boolean]
        $DisableEmailScanning,

        [System.Boolean]
        $DisableRemovableDriveScanning,

        [System.Boolean]
        $DisableRestorePoint,

        [System.Boolean]
        $DisableScanningMappedNetworkDrivesForFullScan,

        [System.Boolean]
        $DisableScanningNetworkFiles,

        [System.Boolean]
        $UILockdown,

        [System.UInt64]
        $ThreatIDDefaultAction_Ids,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $ThreatIDDefaultAction_Actions,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $UnknownThreatDefaultAction,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $LowThreatDefaultAction,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $ModerateThreatDefaultAction,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $HighThreatDefaultAction,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $SevereThreatDefaultAction,

        [ValidateSet("None","Always","Never")]
        [System.String]
        $SubmitSamplesConsent
    )

    if (!(PlatformSupported))
    {
        Throw  "This OS version is not supported. Windows Defender DSC supports Windows 10/Windows Server 2016 and higher versions"
    }

    $Params = $PSBoundParameters

    <#
        When new exclusions are added we want to make sure that old values are removed.
    #>


    if ($Params.ContainsKey('ExclusionPath') -or $Params.ContainsKey('ExclusionProcess') -or $Params.ContainsKey('ExclusionExtension'))
    {
       Handle-Exclusions $Params        
    }
    
    $output = $Params.Remove('IsSingleInstance')
    $output = $Params.Remove('Debug')
    $output = $Params.Remove('Verbose')

    If($PSCmdlet.ShouldProcess($Params.Keys,"Update windows defender configuration"))
    {
        Set-MpPreference @Params
        Write-Verbose "Windows defender configuration successfully updated"
    }
}

<#
    .SYNOPSIS Test state of the resource
    .EXAMPLE
        Test-TargetResource -IsSingleInstance Yes -DisableRealtimeMonitoring $false -Verbose
#>

function Test-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("Yes")]
        [System.String[]]
        $IsSingleInstance,

        [System.String[]]
        $ExclusionPath,

        [System.String[]]
        $ExclusionExtension,

        [System.String[]]
        $ExclusionProcess,

        [ValidateSet("Both","Incoming","Outcoming")]
        [System.String]
        $RealTimeScanDirection,

        [System.UInt32]
        $QuarantinePurgeItemsAfterDelay,

        [ValidateSet("Everyday","Never","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday")]
        [System.String]
        $RemediationScheduleDay,

        [System.DateTime]
        $RemediationScheduleTime,

        [System.UInt32]
        $ReportingAdditionalActionTimeOut,

        [System.UInt32]
        $ReportingNonCriticalTimeOut,

        [System.UInt32]
        $ReportingCriticalFailureTimeOut,

        [System.UInt32]
        $ScanAvgCPULoadFactor,

        [System.Boolean]
        $CheckForSignaturesBeforeRunningScan,

        [System.UInt32]
        $ScanPurgeItemsAfterDelay,

        [System.Boolean]
        $ScanOnlyIfIdleEnabled,

        [ValidateSet("FullSCan","QuickScan")]
        [System.String]
        $ScanParameters,

        [ValidateSet("Everyday","Never","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday")]
        [System.String]
        $ScanScheduleDay,

        [System.DateTime]
        $ScanScheduleQuickScanTime,

        [System.DateTime]
        $ScanScheduleTime,

        [System.UInt32]
        $SignatureFirstAuGracePeriod,

        [System.UInt32]
        $SignatureAuGracePeriod,

        [System.String]
        $SignatureDefinitionUpdateFileSharesSources,

        [System.Boolean]
        $SignatureDisableUpdateOnStartupWithoutEngine,

        [System.String]
        $SignatureFallbackOrder,

        [ValidateSet("Everyday","Never","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday")]
        [System.String]
        $SignatureScheduleDay,

        [System.DateTime]
        $SignatureScheduleTime,

        [System.UInt32]
        $SignatureUpdateCatchupInterval,

        [System.UInt32]
        $SignatureUpdateInterval,

        [ValidateSet("Advanced","Basic","Disabled")]
        [System.String]
        $MAPSReporting,

        [System.Boolean]
        $DisablePrivacyMode,

        [System.Boolean]
        $RandomizeScheduleTaskTimes,

        [System.Boolean]
        $DisableBehaviorMonitoring,

        [System.Boolean]
        $DisableIntrusionPreventionSystem,

        [System.Boolean]
        $DisableIOAVProtection,

        [System.Boolean]
        $DisableRealtimeMonitoring,

        [System.Boolean]
        $DisableScriptScanning,

        [System.Boolean]
        $DisableArchiveScanning,

        [System.Boolean]
        $DisableAutoExclusions,

        [System.Boolean]
        $DisableCatchupFullScan,

        [System.Boolean]
        $DisableCatchupQuickScan,

        [System.Boolean]
        $DisableEmailScanning,

        [System.Boolean]
        $DisableRemovableDriveScanning,

        [System.Boolean]
        $DisableRestorePoint,

        [System.Boolean]
        $DisableScanningMappedNetworkDrivesForFullScan,

        [System.Boolean]
        $DisableScanningNetworkFiles,

        [System.Boolean]
        $UILockdown,

        [System.UInt64]
        $ThreatIDDefaultAction_Ids,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $ThreatIDDefaultAction_Actions,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $UnknownThreatDefaultAction,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $LowThreatDefaultAction,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $ModerateThreatDefaultAction,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $HighThreatDefaultAction,

        [ValidateSet("Allow","Block","Clean","NoAction","Quarantine","Remove","UserDefined")]
        [System.String]
        $SevereThreatDefaultAction,

        [ValidateSet("None","Always","Never")]
        [System.String]
        $SubmitSamplesConsent
    )

    if (!(PlatformSupported))
    {
        Throw  "This OS version is not supported. Windows Defender DSC supports Windows 10/Windows Server 2016 and higher versions"
    }

    $Params = $PSBoundParameters    
    $Return = $True

    $Get = Get-TargetResource -IsSingleInstance $Params.IsSingleInstance

    $Output = $Params.Remove('Debug')
    $Output = $Params.Remove('Verbose')
    $Output = $Params.Remove('IsSingleInstance')

    $Keys = $Get.Keys | ? {$_ -in $Params.Keys}
    
    foreach ($Key in $Keys) 
    {
    
        $InputExclusions = $Params.$key
        $CurrentExclusions = $Get.$key

        <#
            For exclusions we need to compare complete array.
        #>

        if (($Key -eq 'ExclusionPath') -or ($Key -eq 'ExclusionProcess') -or ($Key -eq 'ExclusionExtension'))
        {        
            $Difference = (Compare-Object $CurrentExclusions $InputExclusions).InputObject

            if($Difference)
            {
                $Return = $False
                Write-Verbose "$Key : Input value '$InputExclusions' doesn't match with current value '$CurrentExclusions'"
            }
        
        }
        elseif ($InputExclusions -ne $CurrentExclusions)
        {
            $Return = $False
            Write-Verbose "$Key : Input value '$InputExclusions' doesn't match with current value '$CurrentExclusions'"
        }    
    }

    $Return
}

Export-ModuleMember -Function *-TargetResource


# Helper Functions

function Handle-Exclusions 
{
    param (
        [parameter(Mandatory=$true)][System.Collections.Hashtable] $Params
    )

    $Get = Get-TargetResource -IsSingleInstance $Params.IsSingleInstance

    if ($Params.ContainsKey('ExclusionPath') -and ($Get.ExclusionPath))
    {    
        remove-mppreference -ExclusionPath $Get.ExclusionPath        
    }
    if ($Params.ContainsKey('ExclusionProcess') -and ($Get.ExclusionProcess))
    {    
        remove-mppreference -ExclusionProcess $Get.ExclusionProcess        
    }
    if ($Params.ContainsKey('ExclusionExtension') -and ($Get.ExclusionExtension))
    {    
        remove-mppreference -ExclusionExtension $Get.ExclusionExtension        
    }
}

function Convert-Text 
{
    param(
    [parameter(Mandatory=$true)][Byte]$Val,
    [parameter(Mandatory=$true)][string]$Type
    )
    
    switch ($Type)
    {
        'ScanDirection'
        {
            switch ($Val)
            {
                0 {'Both'}
                1 {'Incoming'}
                2 {'Outcoming'}
            }                
        }
        'ScheduleDay'
        {
            switch ($Val)
            {
                0 {'Everyday'}
                1 {'Sunday'}
                2 {'Monday'}
                3 {'Tuesday'}
                4 {'Wednesday'}
                5 {'Thursday'}
                6 {'Friday'}
                7 {'Saturday'}
                8 {'Never'}
            }
        }
        'ScanParameters'
        {
    
            switch ($Val)
            {
                1 {'Quick scan'}
                2 {'Full scan'}
            }
    
        }
        'MAPSReporting'
        {
            switch ($Val)
            {
                0 {'Disabled'}
                1 {'Basic'}
                2 {'Advanced'}
            }      
        }
        'SubmitSamplesConsent'
        {

            switch ($Val)
            {
                0 {'None'}
                1 {'Always'}
                2 {'Never'}
            }
        }
        'ThreatAction'
        {
            switch ($Val)
            {
                1 {'Clean'}
                2 {'Quarantine'}
                3 {'Remove'}
                6 {'Allow'}
                8 {'UserDefined'}
                9 {'NoAction'}
                10 {'Block'}
            }
        }
    
    }

}

function PlatformSupported
{
    #WindowsDefender DSC is only supported on Windows 10+ and Windows Server 2016+
    if ([System.Environment]::OSVersion.Version.Major -ge 10)
    {
        return $true;
    
    }
    else
    {
        return $false;
    }


}