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!

Update April 12, 2023

Here’s a helpful article with lots of PowerShell commands for checking, disabling, and enabling SMB1, SMB2, and SMB3. Plus a table of what versions are supported in different versions of Windows:

https://woshub.com/smb-1-0-support-in-windows-server-2012-r2/

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

14 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.

  9. Daniel Barber

    I know this is a very very long time from last update or comment, but I am looking for help on this. I have a list of servers, or better yet, would be great if I could cycle through AD looking for servers (To start) and test them one by one and output to a spreadsheet. (I have more than 5000 servers to look at, so not able to do one by one…) I am currently using this (with a SearchBase detailing OU, DC, etc… to get a list of servers names in text output. It would be great to be able to point this script at a text file and have it run server by server based on what is listed in that file….. But I can’t figure that out!

  10. Mark Berry Post author

    @Daniel – How do you manage your servers? Are they in a domain? The core of the script is just setting a registry value. You could do that with Group Policy, or you could use an Remote Monitoring and Management (RMM) tool to deploy a script like this one.

  11. Daniel J Barber

    Long story short, I just started for a large company. All servers 5000+ are managed in a domain. Ultimately everything will be handled with GPO, but to understand the scope of the project (Turn off SMBv1 and NTLMv1) across the enterprise, I would need to create a baseline of servers (An Excel file) with these fields: SMBv1 enabled, yes/no? ,SMBv2 enabled, yes/no? SMBv3 enabled, yes/no? as well as NTLMv1 enable, yes/no? and NTLMv2 enabled yes/no?, I would need to do this across 5000+ servers. Then, as we disable these protocols (VERY CAREFULLY) rerun the scripts to look at progress…. Just 24 hours into trying to figure it all out by looking for scripts that others have worked up so as not to recreate the wheel….. Also likely to use remote monitoring tools, but just looking to create my baseline at this point to know what I am looking at!!!! Thanks for responding…

  12. Mark Berry Post author

    @Daniel – That quantity is way out of my experience but I would think you’d want an RMM tool to be able to manage that kind of scripting and reporting. Don’t some of the “big guys” use System Center? Does that allow running scripts and viewing results? Or maybe SMB management is built in? There are ways to run PowerShell across multiple machines from a management machine, but that requires remote management capabilities and firewall exceptions, which can be problematic on their own.

  13. Nick Thorpe

    Can I modify this script so it outputs to a log file on the C drive ?

  14. Mark Berry Post author

    @Nick, yes, PowerShell can write to the C: drive. I haven’t tested this, but you could try adding this line before the last “Exit $ExitCode” line:

    $Msgs > C:\Windows\temp\SMB1check.log

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.