【问题标题】:Detect SMB1 version via powershell for all OSes通过 powershell 检测所有操作系统的 SMB1 版本
【发布时间】:2021-05-24 23:00:44
【问题描述】:

我的工作流程:

  • 检查服务器是否可以ping通
  • 查找它们是否连接到域并相应地执行任务。如果操作系统 2012 和/或 R2 、2016 或 2019 更新的操作系统,那么我将运行 Get-SmbServerConfiguration cmdlet。如果机器不是默认域的一部分,则else 块将运行。
  • 如果操作系统是 2003 或 2008 最旧的操作系统,那么我将运行 Get-Wmi cmdlet。如果机器不是默认域的一部分,则else 块将运行。

最后,我将集中$results变量。

我的问题是:

1- 我们如何远程获取 2003 年或 2008 年最旧操作系统的注册表值不是默认域 insie else 块的一部分?

另外,条件如下。

 if SMB1 value is "0" then result will be `false`
 if SMB1 value is "1" then result will be `true`
 if SMB1 value is not exist then result will be `not exist value`

2- 如何创建对象属性 $SMBAudit 变量?因为,我会将所有输出集中在 $results 变量中。

$reg = [wmiclass]"\\$computer\root\default:StdRegProv"
$SMBAudit = $reg.GetStringValue($basekey, $subkey, $value).sValue

我想要的输出:

Computername,SMB1Enabled
Host01,True
Host02,False

到目前为止,我将编写如下脚本。但我卡住了一些东西。

脚本:

# Computer List
$allComputers = Get-Content .\path\to\computers.txt

read-host -assecurestring | convertfrom-securestring | out-file C:\mysecurestring_domain.txt

read-host -assecurestring | convertfrom-securestring | out-file C:\mysecurestring_local.txt

# Create empty array of results
$Results = @()

# Loop through computers
foreach($computer in $allComputers) {

    
        # check if server is pingable before running the query on the server
        if (Test-Connection $computer -Count 1 -Quiet) {  

            Write-Host "`n`n$computer is online!" -BackgroundColor Green -ForegroundColor Black
            
        }
        if(Get-ADComputer -Filter {Name -eq $computer -and OperatingSystem -notlike '*Windows*Server*2003*' -and OperatingSystem -notlike '*Windows*Server*2008*'})
            {
        #"machine $_ is a part of default domain"
            # The command we want to run
            
            $username = "domain01\admin01"
$password = Get-Content 'C:\mysecurestring_domain.txt' | ConvertTo-SecureString
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
    $SMB = Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock {Get-SmbServerConfiguration | Select EnableSMB1Protocol }
    
    # Create properties
    $Properties = @{
        # Populate the properties "Computername" and "SMB1Enabled" with variables
        Computername = $Computer
        SMB1Enabled = $SMB.EnableSMB1Protocol

    }
    # Add the properties to the result for each object
    $Results += New-Object psobject -Property $Properties
        
        
        }
        else
        {
        #"machine $_ IS NOT a part of default domain"
        
                    $username = "localadmin01"
$password = Get-Content 'C:\mysecurestring_local.txt' | ConvertTo-SecureString
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
            $SMB = Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock {Get-SmbServerConfiguration | Select EnableSMB1Protocol }
    
    # Create properties
    $Properties = @{
        # Populate the properties "Computername" and "SMB1Enabled" with variables
        Computername = $Computer
        SMB1Enabled = $SMB.EnableSMB1Protocol

    }
    # Add the properties to the result for each object
    $Results += New-Object psobject -Property $Properties
        
        
        
        }
        
        # Oldest OSes

        if(Get-ADComputer -Filter {Name -eq $computer -and OperatingSystem -notlike '*Windows*Server*2012*' -and OperatingSystem -notlike '*Windows*Server*2016*' -and OperatingSystem -notlike '*Windows*Server*2019*'})
            {
        #"machine $_ is a part of default domain"
            # The command we want to run
          <# HKEY_CLASSES_ROOT (2147483648 (0x80000000))
 HKEY_CURRENT_USER (2147483649 (0x80000001))
 HKEY_LOCAL_MACHINE (2147483650 (0x80000002))
 HKEY_USERS (2147483651 (0x80000003))
 HKEY_CURRENT_CONFIG (2147483653 (0x80000005))
 #>
 
        $basekey  = [uint32]'0x80000002'
$subkey   = 'SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters'
$value    = 'SMB1'

$reg = [wmiclass]"\\$computer\root\default:StdRegProv"
$SMBAudit = $reg.GetStringValue($basekey, $subkey, $value).sValue


        
        
        }
        else
        {
        #"machine $_ IS NOT a part of default domain"

        




}

# Output
$Results | Select-Object Computername, SMB1Enabled | Out-File -Filepath c:\temp\smb1-computers.txt

【问题讨论】:

  • 至于这个,How can we get remotely regedit value for 2003 or 2008 oldest OSes IS NOT a part of default domain,这叫做工作组模式远程处理。有许多关于如何设置和使用它的 MSDocs、3rdP 文章、博客、Youtube 视频。否则,MS SysInternals 工具 psexec 会访问您有权访问的远程计算机并执行您需要的操作。

标签: powershell


【解决方案1】:

我认为你过于复杂了,虽然没有经过我的测试,你可以试试这个:

# Computer List
$allComputers = Get-Content '.\path\to\computers.txt'

# get credentials for domain-joined machines and for local machines
$domainCred = Get-Credential -UserName "domain01\admin01" -Message "Please enter the DOMAIN password"
$localCred  = Get-Credential -UserName "localadmin01" -Message "Please enter the LOCAL password"

# loop through the list of computers and collect output in variable $Results
$Results = foreach($computer in $allComputers) {
    # check if server is pingable before running the query on the server
    if (Test-Connection -ComputerName $computer -Count 1 -Quiet) {  
        Write-Host "$computer is online!" -BackgroundColor Green -ForegroundColor Black

        $server = Get-ADComputer -Filter "Name -eq '$computer'" -Properties OperatingSystem -ErrorAction SilentlyContinue
        # if domain joined, use $domainCred, otherwise $localCred
        if ($server) { 
            $cred    = $domainCred
            $version = ([regex]'Windows Server (\d+)').Match($server.OperatingSystem).Groups[1].Value
        } 
        else { 
            $cred    = $localCred
            $info    = Get-WmiObject -ComputerName $computer -Credential $cred -Class Win32_OperatingSystem
            $version = ([regex]'Windows Server (\d+)').Match($info.Caption).Groups[1].Value
        }
        if ($version -eq '2003') {
            # try reading the registry
            try {
                $RegBase = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Computer)
                $RegKey  = $RegBase.OpenSubKey("SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters")
                $SMB     = $RegKey.GetValue("SMB1")
                [PsCustomObject]@{ ComputerName = $computer; SMB1Enabled = ($null -eq $SMB -or [int]$SMB -eq 1) }
            }
            catch {
                [PsCustomObject]@{ ComputerName = $computer; SMB1Enabled = 'Could not read Remote Registry' }
            }
            finally {
                if ($RegBase) { $RegBase.Close() }
                if ($RegKey)  { $RegKey.Close() }
            }
        }
        elseif ($version -eq '2008') {
            # Older OS
            try {
                # try via WinRM
                $SMB = Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock {
                            Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters' -Name SMB1
                       } -ErrorAction Stop
                # output an object
                [PsCustomObject]@{ ComputerName = $computer; SMB1Enabled = ($null -eq $SMB -or [int]$SMB -eq 1) }
            }
            catch {
                # try reading the registry
                try {
                    $RegBase = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Computer)
                    $RegKey  = $RegBase.OpenSubKey("SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters")
                    $SMB     = $RegKey.GetValue("SMB1")
                    [PsCustomObject]@{ ComputerName = $computer; SMB1Enabled = ($null -eq $SMB -or [int]$SMB -eq 1) }
                }
                catch {
                    [PsCustomObject]@{ ComputerName = $computer; SMB1Enabled = 'Could not read Remote Registry' }
                }
                finally {
                    if ($RegBase) { $RegBase.Close() }
                    if ($RegKey)  { $RegKey.Close() }
                }
            }
        }
        else {
            # Newer OS
            $SMB = Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock { Get-SmbServerConfiguration | Select-Object EnableSMB1Protocol }
            # output an object
            [PsCustomObject]@{ ComputerName = $computer; SMB1Enabled = $SMB.EnableSMB1Protocol }
        }
    }
    else {
        Write-Warning "Computer $computer is off-line"
        # output an object anyway, so that in the CSV it is known that the computer didn't ping
        [PsCustomObject]@{ ComputerName = $computer; SMB1Enabled = 'Off-Line' }
    }
}

# Output on screen
$Results | Format-Table -AutoSize

# Output to CSV file
$Results | Export-Csv -Path 'c:\temp\smb1-computers.csv' -NoTypeInformation -UseCulture

【讨论】:

  • 谢谢,但我假设,正则表达式内部存在问题。因为 Get-ADcomputer -> Windows Server 2008 R2 Standard 但它的工作 Get-SmbServerConfiguration blah 而不是 Get-ItemProperty -Path 'HKLM: 这个正则表达式所有 2003 和/或 2008 组合捕获?
  • 同样的问题,Get-ADcomputer -> 适用于 Windows Server 2008 R2 Standard 但它的工作 Get-SmbServerConfiguration blah 而不是 Get-ItemProperty -Path 'HKLM: ,错误消息:`The term 'Get- SmbServerConfiguration' 不被识别为 cmdlet 的名称``所以通常情况下,Get-ItemProperty cmdlet 将为 2008 和/或 2003 服务器运行。所以 2003 、 2008 没有 cmdlet Get-SMB。
  • btw ,如您所知,2003 服务器可以支持 PowerShell 1.0 并且没有 PowerShell 远程处理功能。我的最后一个问题是:假设操作系统是 2003,那么我想运行[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Computer)。我怎样才能做到这一点 ?我怎样才能整合你的脚本? ` $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Computer.Name)$RegKey =$Reg.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\LanmanServer\\Parameters")$SMBAudit = $RegKey.GetValue("SMB1")` ,
  • SMB1 值为“0”则结果为false SMB1 值为“1”则结果为true SMB1 值不存在则结果为true
  • 谢谢顺便说一句,Windows 2008 条件将与 2003 相同。SMB1 值为“0”则结果为假 SMB1 值为“1”则结果为真 SMB1 值不存在则结果为是真的
猜你喜欢
  • 2012-02-05
  • 1970-01-01
  • 1970-01-01
  • 2011-07-08
  • 1970-01-01
  • 1970-01-01
  • 2012-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多