前言

前面我有写过一个场景:定期检查域环境中新加入域客户端,然后告知管理员将其从Computers移至相应的客户端OU

本篇将继续引用该场景,并实现:获取新加入域的客户端按指定计算机命名规则,自动移动至相应 OU 中


环境介绍

这里有个前提条件,就是你所在的环境,必须是有这标准化的计算机命名规则,在此基础之上,才能按固定的规则去实现自动匹配对应 OU 并移动。

我先介绍下我的环境:

  • 用户计算机命名规则:城市简称+固定资产系统的资产编号(如:BJ2022034234,SH2021042034,GZ2020053751....);
  • 计算机 OU 命名规则:我的客户端 OU 结构类似于: Managed Clients\xxCompurers

PowerShell小技巧:通过Powershell定期自动将加域的客户端从 Computers 按规则移动至相应 OU并发送通知至机器人PowerShell小技巧:通过Powershell定期自动将加域的客户端从 Computers 按规则移动至相应 OU并发送通知至机器人


脚本编写

我将脚本分为几个部分:

  1. 获取默认Computers里的所有计算机名单;
  2. 基于计算机名,将其移动到对应的 OU;(如:BJ2022034234BJComputers;SH2021042034SHComputers
    注:这里也有特例,如我的环境中服务器、以及未按计算机命名规则命名的客户端,不能或者不需要自动移动的,需要列出并提示
  3. 完成执行后,通过企业微信机器人发送执行结果;

脚本一、获取 Computers 计算机成员

#OU List
$HashTable = @{
    BJ = "BJComputers"
    CD = "CDComputers"
    CQ = "CQComputers"
    GZ = "GZComputers"
    HZ = "HZComputers"
    NJ = "NJComputers"
    QD = "QDComputers"
    SH = "SHComputers"
    SZ = "SZComputers"
    WH = "WHComputers"
}

Import-Module ActiveDirectory
#Filter
$FilterString = New-Object System.Collections.ArrayList
$Filter = $HashTable.keys | Foreach-Object {
    $FilterString.Add(("Name -Like '{0}*'" -f $_))
}
$Filter = "({0}) -and Enabled -eq 'true'" -f ($FilterString -join " -or ")

#Computers
$Computersbef = Get-ADComputer -SearchBase "CN=Computers,DC=ITPro,DC=cc" -Filter 'Name -ne "YHDMFILE03" -and Enabled -eq "True"' #执行之前的所有 Computers 成员
$PCCountbef = ($Computersbef.Name).count 

$Computers = Get-ADComputer -SearchBase "CN=Computers,DC=ITPro,DC=cc" -Filter $Filter #只符合客户端命名规则的计算机
$PCCount = ($Computers.Name).count

脚本二、将计算机移动至对应 OU

#数组用于保存日志信息
$Logs = New-Object System.Collections.ArrayList
#Move
$Computers | ForEach-Object {
    $Computer = $_
    #echo $Computer.Name
    $TargetOUName = "OU={0}" -f $HashTable[$($Computer.Name.Substring(0, 2))]
    $Targetou = "OU={0},OU=Managed Clients,DC=ITPro,DC=cc" -f $HashTable[$($Computer.Name.Substring(0, 2))]
    Move-ADObject -Identity $Computer.ObjectGUID -TargetPath $Targetou -ErrorAction SilentlyContinue -ErrorVariable MoveToOU

    #Log
    $Log = "Moved {0} to {1} `n" -f $Computer.Name, $TargetOUName
    [void]$Logs.Add($Log)
}
$Computersaft = Get-ADComputer -SearchBase "CN=Computers,DC=ITPro,DC=cc" -Filter 'Name -ne "YHDMFILE03" -and Enabled -eq "True"' #处理完标准命名的计算机后,再次检查Computers的计算机成员
$PCCountaft = ($Computersaft.Name).count # 完成自动移动之后的数量
$SPPCNames = $Computersaft.Name

脚本三、将操作记录通过企业微信机器人发送

$body = "{
    `"msgtype`":`"markdown`",
    `"markdown`":{
    `"content`":`"$content`",
    `"mentioned_list`":[`"jasonhuang`"]  #@成员只能在 text格式下生效,对 MarkDown 不生效。
    }
}"

$chinese = [System.Text.Encoding]::UTF8.GetBytes($body) #这里是解决中文编码问题的即发送中文消息时候使用。

if ($PCCountbef -gt 0) {

    Invoke-RestMethod https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=x -ContentType "application/jsonxxxxxxxxx" -Method Post -Body $chinese
}
else {
    exit
}

逻辑关系

这里由于环境复杂我做了几个判断语句,以便于实现:

  1. 假如有4 台新加域计算机,2 台自动移动完成,2 台移动失败。得告知管理员自动完成的计算机信息,以及未能自动完成的成员信息,并提示相关人员及时处理。并且通过MarkDown的格式将成功失败的操作以不同字体颜色体现;
  2. 假如4 台新加域计算机均自动移动完成,则通过MarkDown的格式告知正常完成,并列出计算机清单;
  3. 假如 4 台均执行失败,则通过MarkDown的格式发送提醒格式的消息,并列出计算机清单;
  4. 假如计划任务执行失败,则将执行该脚本时的报错首行发送给管理员;

最终版

#OU List
Import-Module ActiveDirectory
$HashTable = @{
    BJ = "BJComputers"
    CD = "CDComputers"
    CQ = "CQComputers"
    GZ = "GZComputers"
    HZ = "HZComputers"
    NJ = "NJComputers"
    QD = "QDComputers"
    SH = "SHComputers"
    SZ = "SZComputers"
    WH = "WHComputers"
}

#Filter
$FilterString = New-Object System.Collections.ArrayList
$Filter = $HashTable.keys | Foreach-Object {
    $FilterString.Add(("Name -Like '{0}*'" -f $_))
}
$Filter = "({0}) -and Enabled -eq 'true'" -f ($FilterString -join " -or ")

#Computers
$Computersbef = Get-ADComputer -SearchBase "CN=Computers,DC=ITPro,DC=cc" -Filter 'Name -ne "WinSRV-FILE03" -and Enabled -eq "True"' #执行之前的所有 Computers 成员,并且排除掉指定的 Server
$PCCountbef = ($Computersbef.Name).count 

$Computers = Get-ADComputer -SearchBase "CN=Computers,DC=ITPro,DC=cc" -Filter $Filter #只符合客户端命名规则的计算机
$PCCount = ($Computers.Name).count

#数组用于保存日志信息
$Logs = New-Object System.Collections.ArrayList
#Move
$Computers | ForEach-Object {
    $Computer = $_
    #echo $Computer.Name
    $TargetOUName = "OU={0}" -f $HashTable[$($Computer.Name.Substring(0, 2))]
    $Targetou = "OU={0},OU=Managed Clients,DC=ITPro,DC=cc" -f $HashTable[$($Computer.Name.Substring(0, 2))]
    Move-ADObject -Identity $Computer.ObjectGUID -TargetPath $Targetou -ErrorAction SilentlyContinue -ErrorVariable MoveToOU

    #Log
    $Log = "Moved {0} to {1} `n" -f $Computer.Name, $TargetOUName
    [void]$Logs.Add($Log)
}
#$content = echo "一共有"$PCCount"台计算机加入域,并已自动完成移动至相关OU,清单如下:`n "$Logs""
$Computersaft = Get-ADComputer -SearchBase "CN=Computers,DC=ITPro,DC=cc" -Filter 'Name -ne "YHDMFILE03" -and Enabled -eq "True"' #处理完标准命名的计算机后,再次检查Computers的计算机成员
$PCCountaft = ($Computersaft.Name).count # 完成自动移动之后的数量
$SPPCNames = $Computersaft.Name
# $TotalCount = $PCCountaft + $PCCount

if (($PCCountaft -gt 0) -and ($PCCountbef -gt $PCCountaft)) {
    $content = @"
新增域计算机<font color=\"warning\"> $PCCountbef 台</font>,需手动处理:
        >需手动处理数量:<font color=\"warning\"> $PCCountaft 台</font>
        >未自动处理原因:<font color=\"warning\">非标准计算机命名或为服务器</font>
        >需手动处理计算机名:<font color=\"comment\"> $SPPCNames </font>
        >脚本完成自动处理:<font color=\"info\"> $PCCount 台</font>,记录如下:
        >$logs
"@
}
elseif (($PCCountaft -gt 0) -and ($PCCount -eq 0)) {
    $content = @"
新增域计算机<font color=\"warning\"> $PCCountaft 台</font>,需要手动处理:
        >需手动处理数量:<font color=\"warning\"> $PCCountaft 台</font>
        >未自动处理原因:<font color=\"warning\">非标准计算机命名或为服务器</font>
        >需手动处理计算机名:<font color=\"warning\"> $SPPCNames </font>
"@
}
elseif ($PCCountaft -eq 0 -and ($PCCountbef -gt 0)) {
    $content = @"
新增域计算机<font color=\"info\"> $PCCount 台</font>,已自动完成移动至相关OU。
        >处理记录如下:<font color=\"comment\"> </font>
        >$logs
"@
}

if ($MovetoOU) {
    $MovetoOULogs = ($MovetoOU.Message -split '\n')[0]
    $content = @"
## <font color=\"warning\">计划任务执行失败</font>
        >失败原因:<font color=\"warning\"> $MovetoOULogs </font>
"@
}

$body = "{
    `"msgtype`":`"markdown`",
    `"markdown`":{
    `"content`":`"$content`",
    `"mentioned_list`":[`"jasonhuang`"]
    }
}"

$chinese = [System.Text.Encoding]::UTF8.GetBytes($body) #这里是解决中文编码问题的即发送中文消息时候使用。

if ($PCCountbef -gt 0) {

    Invoke-RestMethod https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxx -ContentType "application/json" -Method Post -Body $chinese
}
else {
    exit
}

效果截图:

PowerShell小技巧:通过Powershell定期自动将加域的客户端从 Computers 按规则移动至相应 OU并发送通知至机器人PowerShell小技巧:通过Powershell定期自动将加域的客户端从 Computers 按规则移动至相应 OU并发送通知至机器人

特别鸣谢: 九叔、彪哥、Summpot 三位大佬的热心帮助(排名不分先后)