How to Programmatically Detect Remote Host SMB Protocol Version Using Windows Command Line/PowerShell


2 views

When connecting to network shares or troubleshooting SMB-related issues, knowing the exact SMB protocol version supported by a remote host is crucial for compatibility and security purposes. Modern Windows systems (Windows 7 and later) provide multiple methods to detect this information programmatically.

The most straightforward approach for Windows 7 SP1 and later (with PowerShell 3.0+):

# First establish a connection to the share (if not already connected)
net use \\remotehost\sharename /user:username password

# Then check active SMB connections
Get-SmbConnection | Where-Object {$_.ServerName -eq "remotehost"} | 
Select-Object ServerName, Dialect

The Dialect property will show the negotiated SMB version:

  • 2.1 - SMB 2.1 (Windows 7)
  • 3.0 - SMB 3.0 (Windows 8/Server 2012)
  • 3.1.1 - SMB 3.1.1 (Windows 10/Server 2016+)

For hosts where you can't establish a connection, packet capture reveals SMB negotiation:

# Install Wireshark if needed
choco install wireshark -y

# Capture traffic to remote host (run as Administrator)
& "C:\Program Files\Wireshark\tshark.exe" -i Ethernet -f "host remotehost and port 445" -w smb_capture.pcap

Analyze the capture file and look for SMB2 Negotiate Protocol in the first few packets.

For advanced discovery across multiple hosts:

# Install Nmap if needed
choco install nmap -y

# Run SMB version detection scan
nmap --script smb-protocols -p445 remotehost

Sample output:

Host script results:
| smb-protocols: 
|   dialects: 
|     NT LM 0.12 (SMBv1) [dangerous, should disable]
|     2.02
|     2.10
|     3.00
|     3.02
|_    3.11

For previously established connections, check Event Viewer:

# PowerShell command to check SMB client events
Get-WinEvent -LogName "Microsoft-Windows-SMBClient/Operational" | 
Where-Object {$_.Message -like "*remotehost*"} | 
Select-Object TimeCreated, Message -First 10

When testing SMB versions:

  • Disable SMBv1 if detected (security risk)
  • Use encrypted SMB 3.x versions when possible
  • Consider network isolation when testing

Here's a PowerShell function for bulk checking:

function Test-SmbVersion {
    param(
        [string[]]$ComputerName,
        [PSCredential]$Credential
    )

    $results = @()
    foreach ($computer in $ComputerName) {
        try {
            $session = New-PSSession -ComputerName $computer -Credential $Credential -ErrorAction Stop
            $smbInfo = Invoke-Command -Session $session -ScriptBlock {
                Get-SmbServerConfiguration | Select-Object EnableSMB1Protocol, EnableSMB2Protocol
            }
            $results += [PSCustomObject]@{
                ComputerName = $computer
                SMB1Enabled = $smbInfo.EnableSMB1Protocol
                SMB2Enabled = $smbInfo.EnableSMB2Protocol
                Status = "Success"
            }
        } catch {
            $results += [PSCustomObject]@{
                ComputerName = $computer
                SMB1Enabled = $false
                SMB2Enabled = $false
                Status = "Error: $_"
            }
        }
    }
    return $results
}

When troubleshooting network file sharing or security auditing, identifying the SMB protocol version of a remote host is crucial. Windows provides several built-in tools that can help determine this information without requiring direct access to the target system.

The most reliable way to check SMB versions is through PowerShell's Test-NetConnection combined with packet analysis:


# First, establish if SMB port is open
$smbPortOpen = Test-NetConnection -ComputerName remotehost -Port 445

if ($smbPortOpen.TcpTestSucceeded) {
    # Use .NET sockets to initiate SMB negotiation
    $socket = New-Object System.Net.Sockets.TcpClient('remotehost', 445)
    $stream = $socket.GetStream()
    
    # Send SMB negotiate protocol request
    $negotiatePacket = [byte[]]@(
        0x00, 0x00, 0x00, 0x85, 0xFF, 0x53, 0x4D, 0x42, 
        0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x53, 0xC8, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x02, 
        0x50, 0x43, 0x20, 0x4E, 0x45, 0x54, 0x57, 0x4F, 
        0x52, 0x4B, 0x20, 0x50, 0x52, 0x4F, 0x47, 0x52, 
        0x41, 0x4D, 0x20, 0x31, 0x2E, 0x30, 0x00, 0x02, 
        0x4C, 0x41, 0x4E, 0x4D, 0x41, 0x4E, 0x31, 0x2E, 
        0x30, 0x00, 0x02, 0x57, 0x69, 0x6E, 0x64, 0x6F, 
        0x77, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x57, 
        0x6F, 0x72, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x70, 
        0x73, 0x20, 0x33, 0x2E, 0x31, 0x61, 0x00, 0x02, 
        0x4C, 0x4D, 0x31, 0x2E, 0x32, 0x58, 0x30, 0x30, 
        0x32, 0x00, 0x02, 0x4C, 0x41, 0x4E, 0x4D, 0x41, 
        0x4E, 0x32, 0x2E, 0x31, 0x00, 0x02, 0x4E, 0x54, 
        0x20, 0x4C, 0x4D, 0x20, 0x30, 0x2E, 0x31, 0x32, 
        0x00
    )
    $stream.Write($negotiatePacket, 0, $negotiatePacket.Length)
    
    # Read response to determine SMB version
    $response = New-Object byte[] 1024
    $bytesRead = $stream.Read($response, 0, $response.Length)
    $socket.Close()
    
    # Analyze response
    if ($response[4] -eq 0xFF -and $response[5] -eq 0x53 -and $response[6] -eq 0x4D -and $response[7] -eq 0x42) {
        $smbVersion = "$($response[8]).$($response[9])"
        Write-Host "Detected SMB version: $smbVersion"
    }
} else {
    Write-Warning "Remote host does not have SMB port (445) open"
}

For more comprehensive scanning, you can use Nmap with its SMB scripts:


nmap --script smb-protocols -p 445 remotehost

Sample output would indicate supported versions:


Host script results:
| smb-protocols: 
|   dialects: 
|     NT LM 0.12 (SMBv1) [dangerous, but default on some old systems]
|     2.02
|     2.10
|     3.00
|     3.02
|_    3.1.1

SMB version numbers correspond to:

  • 1.0: Original SMB (obsolete and insecure)
  • 2.0: Introduced with Windows Vista/Server 2008
  • 2.1: Windows 7/Server 2008 R2
  • 3.0: Windows 8/Server 2012
  • 3.1.1: Windows 10/Server 2016 and later

Remember that SMBv1 is deprecated and dangerous. If you detect it, consider upgrading or disabling it:


# Disable SMBv1 on Windows client
Disable-WindowsOptionalFeature -Online -FeatureName smb1protocol

For servers, use:


Set-SmbServerConfiguration -EnableSMB1Protocol $false

For regular auditing, create a CSV report of multiple hosts:


$hosts = 'server1','server2','fileshare1'
$results = foreach ($host in $hosts) {
    try {
        $socket = New-Object System.Net.Sockets.TcpClient($host, 445)
        $stream = $socket.GetStream()
        # ... (same negotiation code as above)
        [PSCustomObject]@{
            Hostname = $host
            SMBVersion = $smbVersion
            Timestamp = Get-Date
        }
    } catch {
        [PSCustomObject]@{
            Hostname = $host
            SMBVersion = 'Unreachable'
            Timestamp = Get-Date
        }
    }
}
$results | Export-Csv -Path 'smb_audit.csv' -NoTypeInformation