【问题标题】:Find next available computer name查找下一个可用的计算机名称
【发布时间】:2012-11-21 11:49:50
【问题描述】:

我正在尝试在外域中查找下一个可用的计算机名称。我们的计算机使用命名格式 部门名称001

部门名称003

部门名称004

...

部门名称999

我可以找到现有的计算机帐户并添加 1,但我无法让它开始查看 001,我知道"{0:d3}" -f 的使用,但我没有正确使用它。有人可以帮忙吗?

function GetComputerList($ComputerName)
{
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = “LDAP://dc=domain,dc=local”
$objSearcher.Filter = ("(&(objectCategory=computer)(name=$ComputerName))")
$colProplist = "name"
$objSearcher.PageSize = 1000
    foreach ($i in $colPropList){[void]$objSearcher.PropertiesToLoad.Add($i)}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
    {$objComputer = $objResult.Properties; $objComputer.name}
}


$HostName = Finance
$unit="{0:d3}" -f $_

$num = GetComputerList("$HostName*") | Foreach {[int]($_.Name)} | Sort-Object | Select-Object -Last 1 
$name = $HostName+($unit+($num+1))

【问题讨论】:

    标签: powershell


    【解决方案1】:

    试试这个,它会获取所有名称以“departmentName”开头的计算机,去除所有 a-z 字符,只留下数字,将数字转换为整数并对它们进行排序以找到最大的一个:

    $searcher = [ADSISearcher]'(&(objectCategory=computer)(name=departmentName*))'
    $searcher.PageSize = 1000
    $last = $searcher.FindAll() | Foreach-Object { [int]($_.Properties.name -replace '\D').Trim() } | Sort-Object | Select-Object -Last 1
    $digitLength = "$last".Length
    $NewComputerName = "{0}{1:D$digitLength}" -f 'departmentName',($last+1)
    $NewComputerName 
    

    编辑:

    # get next available number in a range of numbers. returns 5 for 1,2,3,4,6,7,9
    $number = $searcher.FindAll() | Foreach-Object { [int]($_.Properties.name -replace '\D').Trim() } | Sort-Object    
    
    for($i=0; $i -lt $number.length; $i++) {if( $number[$i+1]-$number[$i] -gt 1) {$number[$i]+1; break} }
    

    【讨论】:

    • 感谢您的建议,但它并不能完全执行任务。具体来说,它会移动到最大值,那里可能有一个较小的可用值(例如计算机 1、3、4、5、6、7、8、9,它将使用 10,而不是 2)。更重要的是,它不会像 {0:d3} 那样用前导零 000 填充。因此,如果您使用“Finance”并且不存在“Finance*”机器,则它以 Finance1 而不是 Finance001 开头,如果您使用名称 Sales,其中 Sales 的姓氏是 Sales047,它会选择名称 Sales48(没有前导 0)
    【解决方案2】:

    试试这个:

    $searcher = [ADSISearcher]'(&(objectCategory=computer)(name=Finance*))'
    $searcher.PageSize = 1000
    $last = $searcher.FindAll() | Foreach-Object {
    [string]($_.Properties.name -replace '\D')  }  | Sort-Object     
    $i = 0
    $last | % { if ($i -ne [int]$_ ) { $new = $i.tostring().padleft(3,'0'); break } 
    else 
    { $i++ }}
    
    $newComputerName = "finance" + $new 
    

    【讨论】:

      【解决方案3】:

      根据这篇文章中的信息,我对我的环境的代码进行了一些更改和调整,以检查的不仅仅是 AD.. 并且还修复了它在范围开始时不填充空白.. 我有在这里写博客:AutoGeneratingServer Names

      这里也是代码的副本,我知道它可以重构很多!

      [CmdletBinding()]
      param()
      
      # ********************************************************
      $startOfName = "xxxYYYZZWEB"
      # ********************************************************
      
      # VMWare Details
      $ADVIServers = @("vsphere1.blah.local","vsphere2.blah.local","vsphere3.blah.local","vsphere4.blah.local")
      $StandAloneHosts = @()
      
      # DNS Details
      $DNSServer = "xxxxxx.blah.local"
      
      # SCCM 2012 Details
      $SCCM2012SiteServer = "sccm2012.blah.local"
      $SCCM2012SiteCode = 'SiteCode' 
      
      # SCCM 2007 Details
      $SCCM2007SiteServer = "sccm2007.blah.local"
      $SCCM2007SiteCode = 'SiteCode2' 
      
      # SCOM 2007 Details
      $SCOMServer = "scom.blah.local"
      
      # Create Empty Arrays
      $VMNumbers = @()
      $ADnumbers = @()
      $DNSNumbers = @()
      $SCCM2012Numbers = @()
      $SCCM2007Numbers = @()
      $SCOM2007Numbers = @()
      
      
      # VMWare
      
          Write-Verbose "Processing VMware"
          Add-PSSnapin vmware.vimautomation.core -ErrorAction SilentlyContinue
      
          # Set options for certificates and connecting to multiple enviroments
          $null = Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$False
          $null = Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -Scope User -Confirm:$False
      
          # Connect to each AD Authenticated viServer
          foreach ($VIServer in $ADVIServers){$null = Connect-VIServer $VIServer -verbose:$false} 
      
          # Connect to standalone host
          foreach ($Host in $StandAloneHosts){$null = Connect-VIServer $Host -User 'usernamehere' -Password 'passwordhere' -verbose:$false} 
      
          # get next available number in a range of numbers.
          $VMNames = Get-VM -Name "$($startOfName)*" -verbose:$false |select Name
          $VMNames |select Name | Foreach-Object {Write-Verbose $_.Name} | Sort-Object
          $VMNumbers = $VMNames |select Name | Foreach-Object {[int]($_.Name -replace '\D').Trim() } | Sort-Object
          Write-Verbose "$($VMNumbers.Count) Matching entries found"
      
      # Active Directory
      
          Write-Verbose "Processing Active Directory"
      
          # Issue Query
          $searcher = [ADSISearcher]"(&(objectCategory=computer)(name=$($StartOfName)*))"
          $searcher.PageSize = 1000
      
          # get next available number in a range of numbers. returns 5 for 1,2,3,4,6,7,9 From AD
          $ADNames = $searcher.FindAll() | Foreach-Object {[string]$_.Properties.name} | Sort-Object
          $ADNames | Foreach-Object {Write-Verbose $_} | Sort-Object  
          $ADnumbers = $ADNames | Foreach-Object {[int]($_ -replace '\D').Trim() } | Sort-Object  
          Write-Verbose "$($ADnumbers.Count) Matching entries found"
      
      # Search DNS
      
          Write-Verbose "Processing DNS"
      
          # Import DNS module
          Import-Module dnsShell -Verbose:$false
          $DNSNames = get-dnsRecord -server $DNSServer -RecordType A -Zone blah.local | select Name |where {$_.Name -like "$($startOfName)*"} 
          $DNSNames | Foreach-Object {Write-Verbose $_.Name} | Sort-Object -Unique
          $DNSNumbers = $DNSNames | Foreach-Object {[int]($_.Name -replace '\D').Trim() } | Sort-Object -Unique
          Write-Verbose "$($DNSNumbers.Count) Matching entries found"
      
      # Search SCCM
      
          Write-Verbose "Processing SCCM 2012"
      
          # Query SCCM2012 Env
          $SCCM2012Members = Get-WmiObject -ComputerName $SCCM2012SiteServer -Namespace  "ROOT\SMS\site_$SCCM2012SiteCode" -Query "SELECT * FROM SMS_FullCollectionMembership WHERE CollectionID='SMS00001' AND Name LIKE '$($startOfName)%' order by name" | select Name -Unique
          $SCCM2012Members |select Name | Foreach-Object {Write-Verbose $_.Name} | Sort-Object
          $SCCM2012Numbers = $SCCM2012Members |select Name | Foreach-Object {[int]($_.Name -replace '\D').Trim() } | Sort-Object
          Write-Verbose "$($SCCM2012Numbers.Count) Matching entries found"
      
          Write-Verbose "Processing SCCM 2007"
      
          # Query SCCM2007 Env
          $SCCM2007Names = Get-WMIObject -ComputerName $SCCM2007SiteServer -Namespace "root\sms\site_$SCCM2007SiteCode" -class "SMS_R_System" -filter "Name LIKE `"$startOfName%`"" |select Name | Sort-Object -Property Name -Unique
          $SCCM2007Names |select Name | Foreach-Object {Write-Verbose $_.Name} | Sort-Object
          $SCCM2007Numbers = $SCCM2007Names |select Name | Foreach-Object {[int]($_.Name -replace '\D').Trim() } | Sort-Object
          Write-Verbose "$($SCCM2007Numbers.Count) Matching entries found"
      
      # Search Production SCOM 2007
      
          Write-Verbose "Processing SCOM 2007"
      
          #Initialize SCOM SnapIn
          Add-PSSnapin Microsoft.EnterpriseManagement.OperationsManager.Client -ErrorAction SilentlyContinue -verbose:$false
      
          #Connect to Production SCOM 2007 Env.
          $null = New-ManagementGroupConnection -ConnectionString $SCOMServer
      
          #Connect to SCOM Provider
          Push-Location 'OperationsManagerMonitoring::'
      
          # Get Agents Matching Name
          $SCOM2007Names = Get-ManagementServer |Get-Agent |Where {$_.Name -like "$($startOfName)*"}
          $SCOM2007Names | Foreach-Object {Write-Verbose $_.Name} | Sort-Object
          $SCOM2007Numbers = $SCOM2007Names | Foreach-Object {[int]($_.Name -replace '\D').Trim() } | Sort-Object
          Write-Verbose "$($SCOM2007Numbers.Count) Matching entries found"
      
          # Return to previous location
          Pop-Location
      
      # Merge arrays adding a zero so we allways start issuing numbers from the beginning (ie 001)
      $list = @(0) + $VMNumbers + $ADnumbers + $DNSNumbers + $SCCM2012Numbers + $SCCM2007Numbers + $SCOM2007Numbers
      
      # Remove Duplicates numbers from the array and sort into numerical order
      $list = $list | Sort-Object -Unique
      
      Write-Verbose "Used numbers after sorting: $($list)"
      
      # Determine if next server name is a gap in the sequence in the array
      for($i=0; $i -lt $list.length; $i++) {
          if( $list[$i+1]-$list[$i] -gt 1) {
              # The gap between the current server number and the next element in the array is greater than 1
              # So we have an available number we can use.
              # TODO: - Add support for consecutive numbers IE build 6 servers with consecutive numbers.
              $num = "{0:000}" -f ($list[$i]+1)
              break
          }
      }
      
      # If no gap found in the sequence then use the next number from the sequence in the array
      if ($num -eq $null) {
          $num = "{0:000}" -f (($list[-1]+1))
      }
      
      # Construct new name
      $NewComputerName = "{0}{1}" -f $startOfName,$num
      
      # Create DNS Record to 'reserve / mark the name as in use'
      Write-Verbose "Creating DNS Reservation"
      New-DnsRecord -Name $NewComputerName -IPAddress "127.0.0.1" -Zone blah.local -Type A -Server $DNSServer
      
      write-output $NewComputerName
      

      【讨论】:

        猜你喜欢
        • 2014-01-07
        • 2015-05-16
        • 1970-01-01
        • 1970-01-01
        • 2015-03-24
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多