You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从计算机列表随机分配至4个AD组,无重复成员脚本问题

问题描述

需要将指定OU中的计算机随机分配至4个AD组,每台计算机仅能归属一个组。但当前编写的PowerShell脚本存在两个问题:

  • 无法正确调用$groupname执行Add-ADGroupMember操作
  • 计算机重复出现在多个组中

现有脚本

$logfile = "results-$((Get-Date).ToString('MM-dd-yyyy_hhmmtt')).log"

Get-Date | Out-File $logfile

$groupnameprefix = "Automated"

$organizationalunitpath="OU paths go here. There are multiple"


$grouporganizationalunitpath = "OU paths for AD Security Groups go here"
$NumberofComputersPerGroup = "300"
# This is a list of computer names that will be used to generate group names
$Patch_Groups = @(
"_Group_1",
"_Group_2",
"_Group_3",
"_Group_4"
)

# Get all computers from the specified organizational unit
[System.Collections.Generic.List[object]] $computers = $organizationalunitpath |
    ForEach-Object { Get-ADComputer -Filter * -SearchBase $_ }

# Create the new group
foreach ($Patch_Group in $Patch_Groups){
# Generate the group name by concatenating the prefix and the Patch Group name with spaces removed
$groupname = $groupnameprefix + $Patch_Group.Replace(" ","")
try {
# Create the group using the generated name and the specified organizational unit path
New-ADGroup -Name $groupName -path $grouporganizationalunitpath -GroupScope Global -verbose
} 

catch { 
         $message = "ADGroup $groupName already exists"
            $message | Out-File $logfile -Append
            Write-Warning $message
            Write-Warning $_.Exception.Message
            $_.Exception.Message | Out-File $logfile -Append
 }


    try {
        $AddComputerstoRandomADGroups = Get-Random -input $computers -count 300
        $computers = $computers | where {$_ -notin $AddComputerstoRandomADGroups}
        Add-ADGroupMember -Identity $groupname -Members $AddComputerstoRandomADGroups -verbose
    
    }
    catch {
        $message = ' A problem occurred trying to add Members'
        $message | Out-File $logfile -Append
        Write-Warning $message
        Write-Warning $_.Exception.Message
        $_.Exception.Message | Out-File $logfile -Append
    }
}

解决思路

一、修复$groupname调用失败问题

  • 统一变量大小写:PowerShell变量区分大小写,脚本里生成的是$groupname(小写n),但创建组时用的是$groupName(大写N),这会导致$groupname未正确赋值,统一改成$groupName即可。
  • 改用组对象而非名称:创建组时加上-PassThru参数直接获取组对象,后续添加成员时用该对象作为-Identity参数,避免因组名重复或识别问题导致失败:
    $group = New-ADGroup -Name $groupName -Path $grouporganizationalunitpath -GroupScope Global -PassThru -Verbose
    Add-ADGroupMember -Identity $group -Members $selectedComputers -Verbose
    
  • 处理组已存在的场景:如果组已存在,直接用Get-ADGroup获取组对象,不要跳过这一步,否则后续添加成员会找不到组。

二、解决计算机重复分配问题

  • 保持集合可修改性:原脚本中$computers是List<object>类型,但用where {$_ -notin ...}过滤后返回的是普通数组,不再是List,导致后续Get-Random还是从原始集合中取值。改用List的RemoveAt方法按索引删除已分配的计算机(注意要倒序删除,避免索引偏移):
    # 随机生成要选中的计算机索引
    $selectedIndices = Get-Random -InputObject (0..($computers.Count-1)) -Count $takeCount
    # 获取选中的计算机
    $selectedComputers = $selectedIndices | ForEach-Object { $computers[$_] }
    # 倒序删除索引,防止前面的删除导致后面的索引错位
    $selectedIndices | Sort-Object -Descending | ForEach-Object { $computers.RemoveAt($_) }
    
  • 替换硬编码数值:把硬编码的300改成变量$NumberofComputersPerGroup,同时将该变量从字符串类型转为整数类型($NumberofComputersPerGroup = 300)。
  • 处理剩余计算机不足的情况:每次分配前计算可分配的数量,取每组应分配数和剩余计算机数的最小值,避免因剩余不足报错:
    $takeCount = [Math]::Min($NumberofComputersPerGroup, $computers.Count)
    

三、其他优化建议

  • 日志输出改用Add-Content更简洁,或者用Start-Transcript记录所有操作日志。
  • 添加计算机总数检查,如果没有找到任何计算机直接退出脚本,避免无效操作。
  • 捕获Get-ADComputer的异常,处理OU路径错误或无权限的情况。

修改后的完整脚本

$logfile = "results-$((Get-Date).ToString('MM-dd-yyyy_hhmmtt')).log"
Get-Date | Out-File $logfile

$groupnameprefix = "Automated"
# 建议改成数组格式,支持多个OU路径
$organizationalunitpath = @("OU=Computers,DC=domain,DC=com", "OU=Laptops,DC=domain,DC=com")
$grouporganizationalunitpath = "OU=PatchGroups,DC=domain,DC=com"
$NumberofComputersPerGroup = 300 # 转为整数类型
$Patch_Groups = @("_Group_1", "_Group_2", "_Group_3", "_Group_4")

# 获取所有目标OU中的计算机,存入List以便修改
[System.Collections.Generic.List[object]] $computers = @()
foreach ($ou in $organizationalunitpath) {
    try {
        $ouComputers = Get-ADComputer -Filter * -SearchBase $ou -ErrorAction Stop
        $computers.AddRange($ouComputers)
    }
    catch {
        $message = "获取OU [$ou] 的计算机失败: $($_.Exception.Message)"
        $message | Out-File $logfile -Append
        Write-Warning $message
    }
}

# 检查是否有计算机
if ($computers.Count -eq 0) {
    $message = "未找到任何计算机,脚本终止"
    $message | Out-File $logfile -Append
    Write-Warning $message
    exit
}

foreach ($Patch_Group in $Patch_Groups) {
    $groupName = $groupnameprefix + $Patch_Group.Replace(" ", "")
    $group = $null

    # 创建或获取组对象
    try {
        $group = New-ADGroup -Name $groupName -Path $grouporganizationalunitpath -GroupScope Global -PassThru -Verbose -ErrorAction Stop
        $message = "成功创建组: $groupName"
        $message | Out-File $logfile -Append
    }
    catch {
        if ($_.Exception.Message -match "已存在|already exists") {
            $message = "组 $groupName 已存在,直接获取组对象"
            $message | Out-File $logfile -Append
            Write-Warning $message
            try {
                $group = Get-ADGroup -Filter { Name -eq $groupName } -SearchBase $grouporganizationalunitpath -ErrorAction Stop
            }
            catch {
                $message = "获取已存在组 $groupName 失败: $($_.Exception.Message)"
                $message | Out-File $logfile -Append
                Write-Warning $message
                continue # 跳过该组的成员添加
            }
        }
        else {
            $message = "创建组 $groupName 失败: $($_.Exception.Message)"
            $message | Out-File $logfile -Append
            Write-Warning $message
            continue
        }
    }

    # 分配计算机到组
    try {
        $takeCount = [Math]::Min($NumberofComputersPerGroup, $computers.Count)
        if ($takeCount -eq 0) {
            $message = "没有剩余计算机可分配给组 $groupName"
            $message | Out-File $logfile -Append
            Write-Warning $message
            continue
        }

        # 随机选择计算机索引
        $selectedIndices = Get-Random -InputObject (0..($computers.Count-1)) -Count $takeCount
        $selectedComputers = $selectedIndices | ForEach-Object { $computers[$_] }

        # 删除已选中的计算机
        $selectedIndices | Sort-Object -Descending | ForEach-Object { $computers.RemoveAt($_) }

        # 添加成员到组
        Add-ADGroupMember -Identity $group -Members $selectedComputers -Verbose -ErrorAction Stop
        $message = "成功向组 $groupName 添加 $takeCount 台计算机"
        $message | Out-File $logfile -Append
    }
    catch {
        $message = "向组 $groupName 添加成员失败: $($_.Exception.Message)"
        $message | Out-File $logfile -Append
        Write-Warning $message
    }
}

$message = "脚本执行完成,剩余未分配计算机数量: $($computers.Count)"
$message | Out-File $logfile -Append
Write-Host $message

内容的提问来源于stack exchange,提问作者user3911968

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:04:54