PowerShell Script to Check and Disable SMBv1

SMBv1 is an old network protocol targeted by the now-infamous WannaCry virus. Although the issue exploited by WannaCry was patched in March 2017, SMBv1 was left enabled by default, leaving open a security hole for the next possibly unpatched vulnerability. It is therefore considered best practice to stop using SMBv1 on all Windows machines.


Before disabling SMBv1, you might want to use a packet sniffer to check whether any devices are still using it. This TechNet article discusses how to do it with Microsoft Message Analyzer, but WireShark has a nice “smb” display filter as well.

When you’re ready to disable SMBv1, you’ll come across Microsoft KB2696547 with instructions, but you won’t find a script or program there. I’ve therefore developed a PowerShell script that should (*) issue the correct commands on machines from Vista/Server 2008 and above.

The script can be run standalone or from a Remote Monitoring and Management dashboard like Solarwinds MaxRM. If you are using MaxRM, output will be saved in the dashboard for review. The top line shows whether SMBv1 is enabled. Click on the blue link to show details about what the script did:

Disable SMBv1

The first time the script runs, it will check for SMBv1, disable it if it is enabled, then check again. Subsequent runs should find that it is no longer enabled.

If you want to check for SMBv1 without disabling it, run the script with the first parameter = $false.

(*) Use at your own risk!

The Script

Copy and paste the script to a text file e.g. “CheckDisableSMBv1.ps1”. Run it on the machines where you need to disable SMBv1. If you’d like help deploying it in your environment, contact MCB Systems.

<#
.Synopsis
  Check for SMBv1 on Windows Vista/2008 and higher6.  Optionally (and by default) 
  disable SMBv1, which requires Administrator privilege.
  
  Reference:  https://support.microsoft.com/en-us/help/2696547/
  That article recommends using Get/Set-SmbServerConfiguration for Windows 8
  and higher, and a registry value for Windows 7 and below.  In testing, it
  looks like Get/Set-SmbServerConfiguration just checks/updates the same 
  registry value, but this script follows the official guideline.
  
  Copyright (c) 2017 by MCB Systems. All rights reserved.
  Free for personal or commercial use.  May not be sold.
  No warranties.  Use at your own risk.

.Notes 
    Name:       MCB.CheckDisableSMBv1.ps1
    Author:     Mark Berry, MCB Systems
    Created:    05/17/2017
    Last Edit:  05/18/2017
  
  Changes
  05/18/2017 Set default for $DisableSMBv1 to $true.
             Move logic into functions.
             Check for Administrator privilege before attempting disable.
             Re-check SMBv1 after disabling to confirm.

.Parameter DisableSMBv1
    Whether to send an email listing the output.
    Valid values: $true, $false (boolean values)
    Default:  $true
.Parameter LogFile
    Path to a log file. Required by MaxRM script player.  Not used here.
    Default:  "".
#>
param(
  [Parameter(Mandatory = $false,
                    Position = 0,
                    ValueFromPipelineByPropertyName = $true)]
  [Boolean]$DisableSMBv1=$true,

  [Parameter(Mandatory = $false,
                    Position = 1,
                    ValueFromPipelineByPropertyName = $true)]
  [String]$LogFile=""
)

#################################################################
# Functions
#################################################################

# From http://www.jonathanmedd.net/2014/01/testing-for-admin-privileges-in-powershell.html
function Test-IsAdmin {
  ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
}

function CheckSMBv1( `
  [Boolean]$Win8OrHigher, `
  [ref]$Msgs) {

  if ($Win8OrHigher) {
    # Windows 8/2012 or higher
    $ReturnValue = (Get-SmbServerConfiguration).EnableSMB1Protocol
    # Note that to update [ref] variables in a function, you must use the .Value property
    $Msgs.Value += "Get-SmbServerConfiguration return value = $ReturnValue`n"
    $SMBv1Found = ( $ReturnValue -eq "True")
  } else {
    # Windows 7/2008R2 or Vista/2008
    # SMBv1 is enabled by default, so if registry value is missing or = 1, SMBv1 is enabled.
    # Only if the registry key is present and = 0 is SMBv1 disabled.  
    # Next line returns $null if registry key is missing, else returns value of "SMB1" (DWORD 0 or 1)
    $ReturnValue = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" SMB1 -ErrorAction SilentlyContinue).SMB1
    if ($ReturnValue -eq $null) {
      $Msgs.Value += 'Registry value SMB1 is missing (default = 1)' + "`n"
    } else {
      $Msgs.Value += "Registry value SMB1 = $ReturnValue`n"
    }
    $SMBv1Found = ( $ReturnValue -ne 0 )
  }

  if ($SMBv1Found) { 
    $Msgs.Value += "That means SMBv1 is ENabled on $env:computername`n"
  } else {
    $Msgs.Value += "That means SMBv1 is NOT enabled on $env:computername`n"
  }
  
  $SMBv1Found # return $true if found
}

function DisableSMBv1( `
  [Boolean]$Win8OrHigher, `
  [ref]$Msgs) {

  if ($Win8OrHigher) {
    $Msgs.Value += "Disabling SMBv1 with Set-SmbServerConfiguration`n"
    Set-SmbServerConfiguration -EnableSMB1Protocol $false -Force
  } else {
    $Msgs.Value += "Disabling SMBv1 by setting registry value SMB1 = 0`n"
    Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" SMB1 -Type DWORD -Value 0 -Force
  }
}

#################################################################
# Main code
#################################################################

[Boolean]$SMBv1Found = $false
$ExitCode = 0
$Msgs = ""

# Cast $OSVersion as type [Version] so we can compare correctly 
# when major version has two digits (Windows 10 >= 10.0.10240).
[Version]$OSVersion = (Get-WmiObject -namespace "root\CIMV2" `
  -Class win32_OperatingSystem -Property Version `
  -ErrorAction SilentlyContinue -ErrorVariable CmdletErrors).Version

# Gracefully handle WMI errors
if ($CmdletErrors.Count -gt 0) {
  $ExitCode = 1001
  foreach ($CmdletError in $CmdletErrors) {
    if ($CmdletError -is [System.Management.Automation.CmdletInvocationException]) {
      # CmdletInvocationException has .Message property
      $Msgs += $EventLogComputer + " - WMI OS check:  " + $CmdletError.Message + "`n"
    }
    else {
      # ErrorRecord object has .Exception.Message property
      $Msgs += $EventLogComputer + " - WMI OS check:  " + $CmdletError.Exception.Message + "`n"
    }
  }

} else {

  # WMI okay so we have $OSVersion

  # Set version flag
  if ($OSVersion -ge [Version]"6.2.0000") {
    # Windows 8/2012 or higher
    [Boolean]$Win8OrHigher = $true
    $Msgs += "`nOS version $OSVersion : Windows 8/2012 or higher - use Get/Set-SmbServerConfiguration`n"
  } else {
    [Boolean]$Win8OrHigher = $false
    # Windows 7/2008R2 or Vista/2008
    $Msgs += "`nOS version $OSVersion : Windows 7/2008R2 or lower - check/update registry`n"
  }

  # Check for SMBv1
  $SMBv1Found = CheckSMBv1 $Win8OrHigher ([ref]$Msgs)

  # Disable SMBv1 if requested
  if ($SMBv1Found) { 
    if ($DisableSMBv1) { # disable requested
      if (!(Test-IsAdmin)){
        $Msgs += 'You specified DisableSMBv1 = $true (the default) but the script was not run with Administrator privileges.' + "`n"
        $Msgs += "Please re-run as Administrator to disable SMBv1.`n"
      } else {    
        DisableSMBv1 $Win8OrHigher ([ref]$Msgs)
        $Msgs += "Re-check for SMBv1 to confirm that it has been disabled`n"
        $SMBv1Found = CheckSMBv1 $Win8OrHigher ([ref]$Msgs)
      }
    } else {
      $Msgs += 'Re-run this script with the first parameter = $true to disable SMBv1' + "`n"
    }
  }

  # Final messages
  if ($SMBv1Found) { 
    $ExitCode = 1001 # Raise error in MaxRM dashboard if SMBv1 found
    # Display final status _first_ to put in first line of MaxRM dashboard
    if ($DisableSMBv1) { # disable requested
      $Msgs = "SMBv1 is ENabled on $env:computername. Disable was requested but FAILED.`n" + $Msgs
    } else {
      $Msgs = "SMBv1 is ENabled on $env:computername`n" + $Msgs
    }
  } else { 
    $ExitCode = 0   
    $Msgs = "SMBv1 is NOT enabled on $env:computername`n" + $Msgs
  }
}

$Msgs += "`nExiting with ExitCode $ExitCode"
$Msgs # now display messages
Exit $ExitCode

8 thoughts on “PowerShell Script to Check and Disable SMBv1

  1. Mark

    When using this script on Windows 10, it says that SMBv1 is enabled, however it is automatically disabled on Windows 10. Does this mean its active or not?

  2. Mark Berry Post author

    Mark, where are you getting the information that SMBv1 is automatically disabled on Windows 10?

    There is a way to “gracefully remove” SMBv1 in Windows 8.1 and 10, as explained at the bottom of this article:

    https://support.microsoft.com/en-us/help/2696547/how-to-enable-and-disable-smbv1-smbv2-and-smbv3-in-windows-and-windows-server

    So yes, on Windows 8.1 and 10, it’s possible to not only disable SMBv1 but also to uninstall the feature altogether. However, I checked two Windows 10 Pro machines and the SMB 1.0 feature is still checked, so I’m guessing that the feature is enabled/installed by default.

    The script does not disable the SMBv1 feature, though that might be a nice enhancement. For now, it only disables the protocol but leaves the feature unchanged. In other words, it does this:

    Set-SmbServerConfiguration -EnableSMB1Protocol $false -Force

    It does not do this:

    Disable-WindowsOptionalFeature -Online -FeatureName smb1protocol

  3. Tim Meredith

    I modified this script
    taking out the GFI references
    disabling the SMBv1 Client protocol (the original script only disabled the SMBv1 Server protocol)
    writing the results to an event log entry

    Is that okay? I would like to post this on the NinjaRMM forum so that other NinjaRMM users can work with it.

  4. Mark Berry Post author

    Tim – Glad you found this useful. As long as you’re not selling it, I’m fine with your posting a derivative work elsewhere. I’d appreciate a reference back, e.g. “Based on a script by MCB Systems https://www.mcbsys.com.” If the NinjaRMM forum is public, please post a link here–I’d like to see the work you’ve done!

  5. Zrinko

    Mark,

    Thanks for creating this great script. I implemented in in my GFI dashboard and it worked perfectly.

    Thanks,
    Zrinko

  6. Mark Berry Post author

    @Zrinko – I’m always glad when my work helps others–especially colleagues in the local community!

  7. Adam

    Does this deploy well as a startup script or does it require interaction?

  8. Mark Berry Post author

    @Adam, it does not require interaction. I suggest you test it manually before deploying with any automated means.

Leave a Reply

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

Notify me of followup comments via e-mail. You can also subscribe without commenting.

This site uses Akismet to reduce spam. Learn how your comment data is processed.