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

Node+PowerShell导出AD用户数据 如何替代硬编码实现Excel清单

AD域用户信息自动化导出程序优化方案

针对现有程序的硬编码、格式化两个核心问题,直接按以下方案改造即可:

一、消除组判断硬编码

原有逐组写if判断的逻辑完全可以废弃,改用「配置映射+通用过滤」的模式实现:

  • 单独维护一个组配置对象,仅需要标记两类规则:需要自定义显示名称的组、需要忽略不统计的组,其余所有未在配置中出现的AD组会自动保留原名纳入统计,不需要提前枚举所有组。
  • 把PowerShell返回结果的解析逻辑抽成通用函数,删掉原有冗余的数组拷贝、截断逻辑,直接过滤空行和PowerShell默认输出的表头行即可。
  • 组匹配时不需要逐组写includes判断,直接遍历用户所属组列表,按配置规则转换后输出有效组数组即可。

核心改造代码(替换ADPropertiesFunction.mjs对应部分):

// 组规则配置,仅需维护此处即可,新增规则无需修改业务逻辑
const GROUP_RULES = {
  // 格式:AD组原名: 显示名,显示名为空字符串代表忽略该组不统计
  "bitbucket-users": "Bitbucket User",
  "confluence-users": "Confluence User",
  "LoggedInViaOidcSso": "",
  "jira-software-users": "Jira User",
  "jira-servicedesk-users": "Jira Service Desk User",
  "Group Policy Creator Owners": "Group Policy Creator Owners",
  "Domain Admins": "Domain Admins",
  "Enterprise Admins": "Enterprise Admins",
  "Schema Admins": "Schema Admins",
  "Administrators": "Administrators",
  "Guests": "Guest",
  "Denied RODC Password Replication Group": "",
  "confluence-administrators": "Confluence Administrator",
  "bitbucket-system-administrators": "Bitbucket System Administrator",
  "jira-system-administrators": "Jira System Administrator"
}

// 通用解析PowerShell命令返回结果
const parsePsResult = (rawBuffer) => {
  return rawBuffer.toString()
    .split(/\r?\n/)
    .map(line => line.trim())
    .filter(line => line && !line.startsWith("Name") && !line.startsWith("----"))
}

const searchUsers = () => {
  console.log("Loading AD user list...");
  const rawUserResult = execSync("./searchUsers.ps1", { shell: "powershell.exe" })
  return parsePsResult(rawUserResult)
}

const getUserProperties = (username) => {
  const rawUserInfo = execSync(`Get-ADUser ${username} -Properties DistinguishedName | Select-Object Name,DistinguishedName`, {shell: "powershell.exe"})
  // 解析用户DN属性
  const userLines = parsePsResult(rawUserInfo)
  const dn = userLines.find(line => line.startsWith("DC="))
  // 获取用户所属有效组
  const rawGroupResult = execSync(`./FindADUserGroup.ps1 ${username}`, { shell: "powershell.exe" })
  const allGroups = parsePsResult(rawGroupResult)
  const validGroups = allGroups
    .map(g => GROUP_RULES.hasOwnProperty(g) ? GROUP_RULES[g] : g)
    .filter(g => g)
  return {
    name: username,
    DistinguishedName: dn,
    groups: validGroups
  }
}

二、实现Excel勾选矩阵格式输出

原有每个用户占3行、所有组塞单个单元格、每写一个用户开关一次Excel的逻辑性能极差,改造为一次性写入的矩阵格式:

  1. 先拉取所有用户的信息和所属组,遍历所有用户的组列表,去重得到全量组集合,作为Excel的动态表头,不需要提前固定列。
  2. Excel固定前两列为Name、DistinguishedName,从第三列开始依次排列所有收集到的组。
  3. 每个用户占单独一行,对应组列位置如果用户属于该组填1,否则填0。
  4. 整个写入过程只打开一次Excel文件,写完所有数据后统一保存关闭,同时释放COM对象,避免后台残留Excel进程。

改造后的PowerShell写入脚本(替换原有ADPropertiesFunction.ps1):

param(
  [string]$ConfigJson
)
$config = $ConfigJson | ConvertFrom-Json
Import-Module ActiveDirectory
$ExcelObj = New-Object -ComObject Excel.Application
$ExcelObj.Visible = $false
$ExcelWorkBook = $ExcelObj.Workbooks.Open($config.ExcelPath)
$ExcelWorkSheet = $ExcelWorkBook.Sheets.Item("Sheet1")
$ExcelWorkSheet.Activate()

# 写入表头
$ExcelWorkSheet.Cells.Item(1, 1) = "Name"
$ExcelWorkSheet.Cells.Item(1, 2) = "DistinguishedName"
for ($i = 0; $i -lt $config.AllGroupColumns.Count; $i++) {
  $ExcelWorkSheet.Cells.Item(1, $i + 3) = $config.AllGroupColumns[$i]
}

# 写入用户数据
for ($rowIdx = 0; $rowIdx -lt $config.UserListData.Count; $rowIdx++) {
  $currentRow = $rowIdx + 2
  $user = $config.UserListData[$rowIdx]
  $ExcelWorkSheet.Cells.Item($currentRow, 1) = $user.name
  $ExcelWorkSheet.Cells.Item($currentRow, 2) = $user.DistinguishedName
  for ($colIdx = 0; $colIdx -lt $config.AllGroupColumns.Count; $colIdx++) {
    $cellValue = if ($user.groups -contains $config.AllGroupColumns[$colIdx]) { 1 } else { 0 }
    $ExcelWorkSheet.Cells.Item($currentRow, $colIdx + 3) = $cellValue
  }
}

# 保存清理
$ExcelObj.DisplayAlerts = $false
$ExcelWorkBook.Save()
$ExcelWorkBook.Close($true)
$ExcelObj.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelObj) | Out-Null

对应的JS侧主逻辑调整为:

const main = () => {
  const userList = searchUsers()
  const allUserData = []
  const allGroups = new Set()
  // 拉取所有用户数据,收集全量组
  for (const username of userList) {
    const userProp = getUserProperties(username)
    allUserData.push(userProp)
    userProp.groups.forEach(g => allGroups.add(g))
  }
  const groupColumns = Array.from(allGroups)
  // 一次性把所有数据传给PowerShell写入Excel
  const psParam = JSON.stringify({
    ExcelPath: "C:\\Users\\Administrator\\Downloads\\ADPropertiesVer1\\testADpropertiesVer1.xlsx",
    AllGroupColumns: groupColumns,
    UserListData: allUserData
  })
  execSync(`./ADPropertiesFunction.ps1 '${psParam}'`, {shell: "powershell.exe"})
  console.log(`Export completed, total ${allUserData.length} users, ${groupColumns.length} groups.`)
}

main()

改造后优势

  • 维护成本极低:后续新增AD组、调整组显示名、设置忽略组,仅需修改GROUP_RULES配置即可,不需要动任何业务判断逻辑。
  • 性能提升明显:从原来每个用户调用3次PowerShell、开关1次Excel,改为全流程仅调用N+1次PowerShell、开关1次Excel,百级用户量下导出速度从分钟级降到秒级。
  • 自动适配场景:不需要提前枚举所有AD组,程序会自动收集扫描到的所有组生成列,适配不同域环境的组差异,不需要针对部署环境改代码。
  • 无后台残留:脚本最后增加了COM对象释放逻辑,不会出现导出完成后后台残留大量Excel进程占内存的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:30:48