Arrays 在本地子网中查找可用的设备名称并重命名设备

Arrays 在本地子网中查找可用的设备名称并重命名设备,arrays,windows,powershell,Arrays,Windows,Powershell,这是一个相当复杂和令人讨厌的情况,我正试图解决,所以我会尽量简化 情况:我的组织对远程站点的windows PC使用基于站点的命名约定。这些站点不在域上。命名约定如下: (站点ID)-(设备用途)(设备编号)-(设备型号) 站点ID限制为5个字符。 设备用途限制为2个字符。 设备型号限制为4个字符 因此,示例设备名称可能如下所示: $myIP = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter 'IPEnabled=T

这是一个相当复杂和令人讨厌的情况,我正试图解决,所以我会尽量简化

情况:我的组织对远程站点的windows PC使用基于站点的命名约定。这些站点不在域上。命名约定如下:

(站点ID)-(设备用途)(设备编号)-(设备型号)

站点ID限制为5个字符。 设备用途限制为2个字符。 设备型号限制为4个字符

因此,示例设备名称可能如下所示:

$myIP = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter 'IPEnabled=True' |
        select -Expand IPAddress |
        select -First 1

$deviceNumber = Scan-Subnet $myIP
if ($deviceNumber -ne $null) {
  $newname = $env:COMPUTERNAME -replace $pattern, "`$1$deviceNumber`$3"
  Rename-Computer -NewName $newname -Restart
}
ABCDE-FG12-9876

问题:由于计划不当,许多设备错误地复制了名称的(设备编号)元素。因此,使用上面的示例,我可能在ABCDE站点有两台设备,它们都命名为
ABCDE-FG12-9876
。我需要在不必手动触摸每个设备的情况下修复此问题

计划:我正在编写一个PowerShell脚本,希望执行以下操作:

  • 根据当前计算机的IP地址标识站点的/24子网
  • 使用该子网ping该子网上所有活动的windows计算机,并将它们的计算机名放入一个数组中
  • 根据该阵列中的数据,确定未使用的第一个可用设备(设备编号),重命名设备并重新启动
  • 问题:我已经开始构建阵列并尝试检查其内容,出于我无法理解的原因,它只是将脚本运行的机器的名称添加到阵列中,而没有正确地添加站点子网中的其余机器。我已经阅读了代码,直到我的眼睛交叉,并试图重新使用从StackOverflow和其他网站的样本,我觉得我只是在旋转我的轮胎,一事无成

    对于如何实现我的目标,我当然愿意接受任何形式的备选方案,但作为参考,我的代码目前就在下面,我只是尝试将
    $sitemachines
    的内容输出到屏幕,以验证捕获的信息是否正确

    Function Iterate-Subnet($Subnet) {  #in the format of "10.10.10."
        $arrIPs = @();$arrValid = @() #Creates 2 arrays, one to hold the IP
                                      #addresses and the other to hold confirmed
                                      #Windows machines
        For($x=1; $x -lt 254; $x++) {
            #Starting at 1 and incrementing to 254, each time building a new IP
            #address based on the subnet
            $IPAddress = $Subnet + $x;$arrIPs += $IPAddress
        }
        ForEach ($IPfound in $arrIPs) {
            $ping = Get-WMIObject -Class Win32_PingStatus -Filter "Address='$IPfound'" #Ping each IP address in the subnet
            If ($ping.StatusCode -eq "0") {
                 #Attempt to connect to each online machine using WMI, this
                 #confirms whether it's a Windows machine
                 $checkOS = Get-WMIObject -Class Win32_OperatingSystem -ComputerName "$IPfound" -ErrorAction SilentlyContinue
                 #Add this computer name to the valid array
                 If ($checkOS -ne $null) {$arrValid += @($checkOS.CSName)}
            }
        }
        #Remove any duplicate entries, this accounts for any multihomed machines
        $arrValid = $arrValid | Select-Object -Unique
        #Return the valid array to any script you choose to call this function from
        return $arrValid 
    }
    
    #Split the computer name at the device position number
    #and store the beginning and end into two variables
    $computer = hostname
    $cname1 = $computer.substring(0,8)
    $cname2 = $computer.substring($computer.length -5,5)
    
    #Find and define the site subnet for pingsweep
    #referencing current machine IP Address
    $getip = Test-Connection -ComputerName $computer -Count 1 
    $ip = $getip.IPV4Address.IPAddressToString
    $IPByte = $ip.Split(".")
    $sitesub = ($IPByte[0]+"."+$IPByte[1]+"."+$IPByte[2]+".")
    
    #build and retrieve the list of site machines
    #from the function Iterate-Subnet
    $sitemachines = Iterate-Subnet -Subnet "$sitesub"
    Start-Sleep -s 30
    $sitemachines.length
    $sitemachines
    

    我使用以下方法进行重命名

    $a = Import-Csv c:\ServerNames.csv -Header OldName, NewName
    Foreach ( $Server in $a ) {Rename-Computer -ComputerName $Server.OldName -NewName $Server.NewName -DomainCredential Domain\username -Force -Restart}
    

    现在这有它的缺点,因为你必须给它一个CSV,但是你把旧的名字/IP地址放在第1列,把新的放在第二列,然后运行它。前面的工作较多,但脚本中失败的逻辑较少。

    由于您的所有子网似乎都是/24 IPv4子网,您可以通过让函数获取主机IP地址(字符串)并返回新的(整数)设备号来简化代码:

    $pattern = '^(.{5}-.{2})(\d+)(-.{4})$'
    
    function Scan-Subnet($ip) {
      $bytes = ([ipaddress]$ip).GetAddressBytes()
    
      1..254 | % {
        $bytes[3] = $_
        $addr = [ipaddress]$bytes
    
        if (Test-Connection $addr -Count 1 -ErrorAction SilentlyContinue) {
          Get-WMIObject -Class Win32_OperatingSystem -Computer $addr |
            select @{n='DeviceNumber';e={[int]($_.CSName -replace $pattern,'$2')}} |
            select -Expand DeviceNumber
        }
      } | sort | select -last 1 | % { $_ + 1 }
    }
    
    $pattern
    被定义为一个包含3个组的全局变量,因此它可以用于提取设备编号和生成新名称(见下文)

    主机IP地址可以通过WMI确定,因此您可以这样调用函数:

    $myIP = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter 'IPEnabled=True' |
            select -Expand IPAddress |
            select -First 1
    
    $deviceNumber = Scan-Subnet $myIP
    
    if ($deviceNumber -ne $null) {
      $newname = $env:COMPUTERNAME -replace $pattern, "`$1$deviceNumber`$3"
      Rename-Computer -NewName $newname -Restart
    }
    
    并按如下方式重命名计算机:

    $myIP = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter 'IPEnabled=True' |
            select -Expand IPAddress |
            select -First 1
    
    $deviceNumber = Scan-Subnet $myIP
    
    if ($deviceNumber -ne $null) {
      $newname = $env:COMPUTERNAME -replace $pattern, "`$1$deviceNumber`$3"
      Rename-Computer -NewName $newname -Restart
    }
    
    由于在PowerShell v3之前,
    Rename Computer
    不可用,因此您也可以使用
    netdom

    & netdom $env:COMPUTERNAME /NewName:$newname /Reboot
    

    还在看你的代码。虽然这不是一个问题,但我可以看到一些地方的代码可以变得更简洁。从
    $checkOS
    行中删除
    -ErrorAction SilentlyContinue
    时会发生什么情况?如果WMI失败,则不会填充数组,也不会出现错误。在您的计划中,您有一个站点子网。。。你可以在一个站点中有多个子网(这只是一个吹毛求疵的问题)。现在试试看它会产生什么结果。否-在我们的环境中,每个站点都位于唯一的子网和/或VLAN上。否则,我认为不会有任何机会使此工作正常。尝试了该编辑,并收到大量红色文本,指示在尝试进行WMI连接时出现拒绝访问错误。我在一个共享实验室中工作,所以这是意料之中的-实验室中的其他设备安装了其他配置,并且不会共享相同的用户名/密码凭据。但是,我没有看到共享正确凭据的~10台实验室机器成功—只是失败。您能够在已知机器上运行该命令吗?红色的墙有意义吗?其他设备(如打印机、交换机等)可能会出现一些错误,但我觉得您需要确保WMI不是您的问题。事实上,目标子网内的打印机、IP电话等是我最初抑制错误的原因。然而,当我在一台实验室机器上尝试这一行时,我得到了一个非常意外的错误——它正在回退一个RPC服务不可用错误,错误代码为0x800706BA。我现在将进一步调查此事谢谢你的想法,我希望这会结出硕果!非常感谢您的想法,但这并不能真正消除任何涉及的手工工作。构建CSV只需要手动输入所有数据,而通过脚本避免这一点。在这一点上,我并没有从手动重命名设备中节省大量的时间和精力。这种逻辑看起来非常有希望。我将用它构建一个新版本的脚本,明天第一件事就是试用它。谢谢。回来让你知道-原来这不适合我的需要。此外,显然我们的现场设备运行的是较旧版本的Powershell,我在较大脚本中使用的一些cmdlet不可用。我使用了一个非常简化的版本,它只是将设备编号替换为以前未使用的范围内随机生成的编号。它可能会以极少量的重复名称结束,但这将足够少,我可以手动修复。感谢您的帮助,很抱歉它不起作用。@Darrianseffield FTR,我发布的代码在PowerShell v2及以上版本中应该可以正常工作,除了
    重命名计算机
    ,可以通过调用
    netdom
    来替换。如果你仍然在PowerShell v1上,你应该认真对待