PowerShell: Disable Windows Defender

Simultaneous Uninstalls:

# removeWindowsDefender.ps1
# Version 0.02

$computerNames=@(
  'server1',
  'server2'
)

function removeWindowsDefender($computerNames){
  function uninstallWindefend($computername){
    $session=try{
      New-PSSession $computername -EA Stop
    }catch{
      New-PSSession $computername -SessionOption (New-PSSessionOption -IncludePortInSPN)
    }
    if($session.state -eq 'opened'){
      $result=invoke-command -Session $session -scriptblock{
        $serverOs=(Get-WmiObject Win32_OperatingSystem).Name -match "^Microsoft Windows Server"
        $null=Set-MpPreference -DisableRealtimeMonitoring $True -EA SilentlyContinue
        if($serverOs){          
          $null=Remove-WindowsFeature Windows-Defender-GUI -EA SilentlyContinue
          $null=Remove-WindowsFeature Windows-Defender -EA SilentlyContinue
          return [hashtable]@{$env:computername=(Get-WindowsFeature windows-defender).InstallState -ne 'Installed'}
        }else{
          return [hashtable]@{$env:computername=(Get-MpComputerStatus).AntivirusEnabled -ne $true}
        }       
      }
      Remove-PSSession $session
    }else{
      write-warning "cannot connect to $computername via WinRM"
      $result=[hashtable]@{$env:computername='Unknown'}
    }
    return $result
  }

  $timer=[System.Diagnostics.Stopwatch]::StartNew()
  $jobResults=@()
  $lineBreak=60
  $dotCount=0
  $minute=0
  $processorsCount=(Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors
  $cpuLoad=(Get-WmiObject win32_processor|Measure-Object -property LoadPercentage -Average).Average
  $maxSimultaneousJobs=if($cpuLoad -gt 90){$processorsCount}else{($processorsCount*2)-1} # dynamically limiting concurrent jobs basing on available CPU cores
  write-host "CPU load detected as: $cpuLoad`%`r`nSetting concurrent jobs max count to be $maxSimultaneousJobs"
  foreach($computerName in $computerNames){
      $thisIterationCompleted=$false
      do {
          $jobsCount=(Get-Job -State 'Running').Count
          if ($jobsCount -lt $maxSimultaneousJobs){            
              if($verbose){write-host "Initiating job for $computerName"}
              $null=Start-Job -name $computerName -ScriptBlock {
                  param($uninstallWindefend,$computerName)
                  [scriptblock]::create($uninstallWindefend).invoke($computerName)
              } -Args ${function:uninstallWindefend},$computerName
              $thisIterationCompleted=$true
          }else{
              if($verbose){
                  if($dotCount++ -lt $lineBreak){
                      write-host '.' -NoNewline
                  }else{
                      $minute++
                      write-host "`r`n$minute`t:" -ForegroundColor Yellow -NoNewline
                      $dotCount=0
                      }
              }
              sleep -seconds 1
          }
      }until ($thisIterationCompleted)
  }
  $totalJobsCount=(get-job).count
  $processedCount=0
  while($processedCount -lt $totalJobsCount){
      $completedJobs=get-job|?{$_.State -eq 'Completed'}
      if($completedJobs){
          foreach ($job in $completedJobs){
              $computer=$job.Name
              if($verbose){
                  write-host "`r`n===================================================`r`n$computer job completed with these messages:`r`n===================================================`r`n"
              }
              $jobResult=receive-job -id $job.id
              $jobResults+=,$jobResult
              remove-job -id $job.id -force
              $processedCount++
          }
      }
  }
  $minutesElapsed=[math]::round($timer.Elapsed.TotalMinutes,2)
  $timer.stop()
  write-host "$($computerNames.count) computers were processed in $minutesElapsed minutes."
  return $jobResults #|select -property * -excludeproperty RunspaceId
}

removeWindowsDefender $computerNames

Error:

Remove-WindowsFeature : The request to add or remove features on the specified server failed.
Removal of one or more roles, role services, or features failed.
The referenced assembly could not be found. Error: 0x80073701
    + CategoryInfo          : InvalidOperation: (@{Vhd=; Credent...Name=localhost}:PSObject) [Uninstall-WindowsFeature
   ], Exception
    + FullyQualifiedErrorId : DISMAPI_Error__Failed_Disabling_Updates,Microsoft.Windows.ServerManager.Commands.RemoveW
   indowsFeatureCommand

Success Restart Needed Exit Code      Feature Result
------- -------------- ---------      --------------
False   No             Failed         {}

Resolution:

It’s most likely being caused by a pending reboot. Recommendation is to reboot the server, then install all required Windows patches. Repeat reboots if necessary to clear all flags before attempting to run the Remove-WindowsFeature command again.

Convenient Function (sequential execution):

# removeWindowsDefender.ps1
# Version 0.01
$computerNames=@(
  'server1',
  'server2'
)

function removeWindowsDefender($computerNames){
  $results=@()
  foreach($computername in $computernames){
    write-host "Checking $computername..."
    $session=try{
      New-PSSession $computername -EA Stop
    }catch{
      New-PSSession $computername -SessionOption (New-PSSessionOption -IncludePortInSPN)
    }
    if($session.state -eq 'opened'){
      $result=invoke-command -Session $session -scriptblock{
        $null=Set-MpPreference -DisableRealtimeMonitoring $True -EA SilentlyContinue
        $null=Remove-WindowsFeature Windows-Defender-GUI -EA SilentlyContinue
        $null=Remove-WindowsFeature Windows-Defender -EA SilentlyContinue
        return [hashtable]@{$env:computername=(Get-WindowsFeature windows-defender).InstallState -ne 'Installed'}
      }
      Remove-PSSession $session
    }else{
      write-warning "cannot connect to $computername via WinRM"
      $result=[hashtable]@{$env:computername='Unknown'}
    }
    $results+=$result
  }
}

removeWindowsDefender $computerNames
Why?

Even though Windows Defender can run along side Enterprise antivirus software such as McAfee or Norton, it would be necessary to disable it on systems that already have those security applications installed. Here are two automated methods to get this done.

1. PowerShell on Localhost

If this is a Windows Server 2016 or Later, run this command

# Uninstall WinDefend
Remove-WindowsFeature Windows-Defender, Windows-Defender-GUI

On Windows 2012 R2, these commands would have worked

# Disable Defender's Real Time scanning engine
Set-MpPreference -DisableRealtimeMonitoring $True

# Deactivate the scanning engine via registry
Set-ItemProperty -Path "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender" -Name "DisableAntiSpyware" -Value 1 -Force

However, the above lines are no longer valid for Windows 10 & 2016 (source: https://support.microsoft.com/en-us/help/4052623/update-for-windows-defender-antimalware-platform). On KB4052623, Microsoft has changed to registry location of Defender. Hence, Active Directory Group Policy and PowerShell commands to disable this feature are no longer effective.

For those who are interested in security topics, these are the related advisories leading to this change:

  • https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2017-11937
  • https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2017-11940
# My fancy way to check if WinDefend is installed
try{Get-MpComputerStatus;"Windows Defender IS enabled on this system.";}
catch{"Windows Defender is NOT enabled on this system.";}

# This is the better method provided by Michael Shoff
sc query windefend
# Disable it within the registry (failed attempt)
Set-ItemProperty -Path "Registry::HKLM\SOFTWARE\Microsoft\Windows Defender" -Name "DisableAntiSpyware" -Value 1 -Force
# Error
PS C:\Users\tester> Set-ItemProperty -Path "Registry::HKLM\SOFTWARE\Microsoft\Windows Defender" -Name "DisableAntiSpyware" -Value 1 -Force
Set-ItemProperty : Requested registry access is not allowed.
At line:1 char:1
+ Set-ItemProperty -Path "Registry::HKLM\SOFTWARE\Microsoft\Windows Def ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (HKLM\SOFTWARE\Microsoft\Windows Defender:String) [Set-ItemProperty],
SecurityException
+ FullyQualifiedErrorId : System.Security.SecurityException,Microsoft.PowerShell.Commands.SetItemPropertyCommand
# Attempt to set permissions (failed)
$acl = Get-Acl "Registry::HKLM\SOFTWARE\Microsoft\Windows Defender"
$fullControl = New-Object System.Security.AccessControl.RegistryAccessRule ("$env:COMPUTERNAME\Administrators","FullControl","Allow")
$acl.SetAccessRule($fullControl)
2. Group Policy

Run ADUC: Create new GPO as follows:
Computer configuration > Administrative templates > Windows components > Windows Defender > Set these values:

Turn off Windows Defender = Enabled
Real-time protection = Off (optional as Defender has already turned off per the preceding setting)

Please note that this GP instruction is to be applied toward Windows 2016 & 2019. This may not work for Windows 2008, 2012, and Linux.

Leave a Reply

Your email address will not be published. Required fields are marked *