AD内のユーザーアカウントの設定プロパティを一括でcsvに出力する方法

コマンド関連のアイキャッチ画像 IT知識・技術

AD内のユーザーアカウントの設定プロパティを一括でCSVに出力する方法

PowerShell(RSAT: Active Directory)で目的別に出力する4+2パターンをまとめます。

前提条件

  • RSAT: Active Directory をインストール(Windows 10/11)

    Get-WindowsCapability -Name RSAT.ActiveDirectory* -Online

    Add-WindowsCapability -Name RSAT.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 -Online
  • ドメイン参加PC:そのまま実行可。ワークグループPC:-Server-Credential を指定。
  • CSVは UTF-8 で保存。出力メッセージは英語推奨(文字化け回避)。

① 個人:特定の属性だけに絞って出力

最小限の列(基本情報+所属グループ名)をCSVへ。

# ADUserExport_Selected.ps1
param(
  [Parameter(Mandatory=$true)][string]$UserSamAccountName,   # e.g., taro.yamada
  [string]$Server,                                           # e.g., dc1.contoso.com
  [System.Management.Automation.PSCredential]$Credential,
  [string]$ExportPath = ".\UserInfo_Selected.csv"
)

Import-Module ActiveDirectory -ErrorAction Stop

$common = @{ Identity = $UserSamAccountName; Properties='*' }
if ($Server)     { $common.Server     = $Server }
if ($Credential) { $common.Credential = $Credential }

$user = Get-ADUser @common -ErrorAction Stop

# Resolve direct groups to names
$groupNames = @()
if ($user.MemberOf) {
  foreach ($dn in $user.MemberOf) {
    try {
      $gp = @{ Identity=$dn; Properties='Name' }
      if ($Server)     { $gp.Server     = $Server }
      if ($Credential) { $gp.Credential = $Credential }
      $g = Get-ADGroup @gp
      $groupNames += $g.Name
    } catch { $groupNames += $dn }
  }
}

$result = [PSCustomObject]@{
  SamAccountName    = $user.SamAccountName
  UserPrincipalName = $user.UserPrincipalName
  DisplayName       = $user.DisplayName
  Enabled           = $user.Enabled
  Department        = $user.Department
  Company           = $user.Company
  Mail              = $user.Mail
  LastLogonDate     = $user.LastLogonDate
  MemberOf_Names    = ($groupNames | Sort-Object -Unique -join ';')
}

$result | Export-Csv -Path $ExportPath -NoTypeInformation -Encoding UTF8
Write-Output ("Export completed. File: {0}" -f $ExportPath)

② 個人:全属性(展開+日付変換付き/1行)

# ADUserExport_Full.ps1
[CmdletBinding()]
param(
  [Parameter(Mandatory=$true)][string]$UserSamAccountName,
  [string]$Server,
  [System.Management.Automation.PSCredential]$Credential,
  [string]$ExportFolder = "."
)

function Convert-FileTime([object]$v) {
  if ($null -eq $v -or $v -eq '') { return $null }
  try {
    [int64]$t = [int64]$v
    if ($t -le 0 -or $t -eq 9223372036854775807) { return $null } # Never/Not set
    return [DateTime]::FromFileTime($t)
  } catch { return $null }
}
function Convert-If-DateLike([hashtable]$raw,[string]$name,[string]$kind='Auto'){
  if (-not $raw.ContainsKey($name)) { return }
  $val = $raw[$name]; $converted = $null
  switch ($kind) {
    'FileTime' { $converted = Convert-FileTime $val }
    'DateTime' { try { $converted = [DateTime]$val } catch { } }
    default {
      if ($val -is [int64] -or $val -is [int32] -or ($val -is [string] -and $val -match '^\d+$')) {
        $converted = Convert-FileTime $val
      } else { try { $converted = ($val -is [DateTime]) ? $val : [DateTime]$val } catch { } }
    }
  }
  $raw["${name}_Converted"] = $converted
}

Import-Module ActiveDirectory -ErrorAction Stop

$cp = @{ Identity=$UserSamAccountName; Properties='*' }
if ($Server)     { $cp.Server     = $Server }
if ($Credential) { $cp.Credential = $Credential }

$user = Get-ADUser @cp -ErrorAction Stop

# Expand multi-valued
$groupNames = @()
if ($user.MemberOf) {
  foreach ($dn in $user.MemberOf) {
    try {
      $gp=@{ Identity=$dn; Properties='Name' }
      if ($Server)     { $gp.Server     = $Server }
      if ($Credential) { $gp.Credential = $Credential }
      $g=Get-ADGroup @gp
      $groupNames+= $g.Name
    } catch { $groupNames+= $dn }
  }
}
$proxyJoined   = if ($user.ProxyAddresses) { $user.ProxyAddresses -join ';' } else { '' }
$memberOfNames = ($groupNames | Where-Object { $_ } | Sort-Object -Unique) -join ';'
$memberOfDNs   = if ($user.MemberOf) { ($user.MemberOf -join ';') } else { '' }

# Merge single-row
$raw = @{}
($user | Select-Object *).PSObject.Properties | ForEach-Object { $raw[$_.Name] = $_.Value }
$raw['ProxyAddresses_Joined'] = $proxyJoined
$raw['MemberOf_Direct_Names'] = $memberOfNames
$raw['MemberOf_DN_Joined']    = $memberOfDNs

$ft = @('lastLogonTimestamp','lastLogon','lastLogoff','pwdLastSet','badPasswordTime','lockoutTime','accountExpires','msDS-UserPasswordExpiryTimeComputed')
foreach ($n in $ft) { Convert-If-DateLike -raw $raw -name $n -kind 'FileTime' }
$dt = @('whenCreated','whenChanged','LastLogonDate','PasswordLastSet','AccountExpirationDate')
foreach ($n in $dt) { Convert-If-DateLike -raw $raw -name $n -kind 'DateTime' }

$singleRow = [PSCustomObject]$raw
$ts = Get-Date -Format "yyyyMMdd-HHmmss"
$path = Join-Path $ExportFolder ("UserInfo_{0}_{1}.csv" -f $UserSamAccountName,$ts)
$singleRow | Export-Csv -Path $path -NoTypeInformation -Encoding UTF8
Write-Output ("Export completed. File: {0}" -f $path)

③ 一括:グループ/OU配下のユーザーを出力

# ADUserBulkExport.ps1
[CmdletBinding(DefaultParameterSetName='ByGroup')]
param(
  [Parameter(ParameterSetName='ByGroup', Mandatory=$true)][string]$Group, # sAMAccountName or DN
  [Parameter(ParameterSetName='ByGroup')][switch]$Recursive,
  [Parameter(ParameterSetName='ByOU',    Mandatory=$true)][string]$SearchBase, # OU DN
  [string]$Server,
  [System.Management.Automation.PSCredential]$Credential,
  [string]$ExportFolder = "."
)

function Convert-FileTime([object]$v){
  if ($null -eq $v -or $v -eq '') { return $null }
  try { [int64]$t=[int64]$v; if ($t -le 0 -or $t -eq 9223372036854775807){return $null}; return [DateTime]::FromFileTime($t) }
  catch { return $null }
}
function Convert-If-DateLike([hashtable]$raw,[string]$name,[string]$kind='Auto'){
  if (-not $raw.ContainsKey($name)) { return }
  $val=$raw[$name]; $converted=$null
  switch($kind){
    'FileTime' { $converted=Convert-FileTime $val }
    'DateTime' { try{$converted=[DateTime]$val}catch{} }
    default {
      if ($val -is [int64] -or $val -is [int32] -or ($val -is [string] -and $val -match '^\d+$')) {
        $converted=Convert-FileTime $val
      } else { try{ $converted = ($val -is [DateTime]) ? $val : [DateTime]$val }catch{} }
    }
  }
  $raw["${name}_Converted"]=$converted
}

Import-Module ActiveDirectory -ErrorAction Stop
$uCommon=@{ Properties='*' }
if ($Server)     { $uCommon.Server     = $Server }
if ($Credential) { $uCommon.Credential = $Credential }

# Cache group names
$script:__adCache=@{}
function Get-GroupName([string]$dn){
  $key="group|$dn|$Server"
  if ($__adCache.ContainsKey($key)) { return $__adCache[$key] }
  $p=@{ Identity=$dn; Properties='Name' }
  if ($Server)     { $p.Server     = $Server }
  if ($Credential) { $p.Credential = $Credential }
  try { $g=Get-ADGroup @p; $__adCache[$key]=$g.Name; return $g.Name } catch { $__adCache[$key]=$dn; return $dn }
}
function Expand-User($user){
  $gNames=@()
  if ($user.MemberOf) {
    foreach($dn in $user.MemberOf){ $gNames+= Get-GroupName $dn }
    $gNames = $gNames | Where-Object { $_ } | Sort-Object -Unique
  }
  $proxy = if ($user.ProxyAddresses){ $user.ProxyAddresses -join ';' } else { '' }

  $raw=@{}
  ($user|Select-Object *).PSObject.Properties | ForEach-Object { $raw[$_.Name]=$_.Value }
  $raw['ProxyAddresses_Joined']= $proxy
  $raw['MemberOf_Direct_Names']= $gNames -join ';'
  $raw['MemberOf_DN_Joined']   = if ($user.MemberOf){ ($user.MemberOf -join ';') } else { '' }

  $ft=@('lastLogonTimestamp','lastLogon','lastLogoff','pwdLastSet','badPasswordTime','lockoutTime','accountExpires','msDS-UserPasswordExpiryTimeComputed')
  foreach($n in $ft){ Convert-If-DateLike -raw $raw -name $n -kind 'FileTime' }
  $dt=@('whenCreated','whenChanged','LastLogonDate','PasswordLastSet','AccountExpirationDate')
  foreach($n in $dt){ Convert-If-DateLike -raw $raw -name $n -kind 'DateTime' }

  return [PSCustomObject]$raw
}

# Resolve users
$users=@()
if ($PSCmdlet.ParameterSetName -eq 'ByGroup'){
  $gp=@{ Identity=$Group }
  if ($Server)     { $gp.Server     = $Server }
  if ($Credential) { $gp.Credential = $Credential }
  $grp=Get-ADGroup @gp

  $mp=@{ Identity=$grp.DistinguishedName }
  if ($Recursive)  { $mp.Recursive=$true }
  if ($Server)     { $mp.Server     = $Server }
  if ($Credential) { $mp.Credential = $Credential }

  $members = Get-ADGroupMember @mp | Where-Object { $_.objectClass -eq 'user' }
  foreach($m in $members){ $users += Get-ADUser @uCommon -Identity $m.DistinguishedName }
} else {
  $sp=@{ SearchBase=$SearchBase; Filter='*' }
  if ($Server)     { $sp.Server     = $Server }
  if ($Credential) { $sp.Credential = $Credential }
  $users = Get-ADUser @sp @uCommon
}

# Build rows
$rows = foreach($u in $users){ Expand-User $u }

$ts = Get-Date -Format "yyyyMMdd-HHmmss"
$csv = if ($PSCmdlet.ParameterSetName -eq 'ByGroup') { "UserInfo_Group_$($Group -replace '[\\/:*?""<>|]','_')_$ts.csv" } else { "UserInfo_OU_$ts.csv" }
$path = Join-Path $ExportFolder $csv
$rows | Export-Csv -Path $path -NoTypeInformation -Encoding UTF8
Write-Output ("Export completed. Rows: {0}, File: {1}" -f $rows.Count, $path)

④ 日付(FileTime)を人間可読に変換する方法

PowerShell:

$dt = [DateTime]::FromFileTime($user.lastLogonTimestamp)  # 0 / 9223372036854775807 は未設定扱い

Excel:

=(((A1/10000000)/86400) + DATE(1601,1,1))

⑤ 軽量版:監査用(列順固定)

# ADUserExport_Audit.ps1
param(
  [Parameter(Mandatory=$true)][string]$UserSamAccountName,
  [string]$Server,
  [System.Management.Automation.PSCredential]$Credential,
  [string]$ExportPath = ".\UserInfo_Audit.csv"
)

Import-Module ActiveDirectory -ErrorAction Stop

$common = @{ Identity = $UserSamAccountName; Properties='*' }
if ($Server)     { $common.Server     = $Server }
if ($Credential) { $common.Credential = $Credential }

$user = Get-ADUser @common -ErrorAction Stop

# Groups (direct)
$groupNames = @()
if ($user.MemberOf) {
  foreach ($dn in $user.MemberOf) {
    try {
      $gp = @{ Identity=$dn; Properties='Name' }
      if ($Server)     { $gp.Server     = $Server }
      if ($Credential) { $gp.Credential = $Credential }
      $g = Get-ADGroup @gp
      $groupNames += $g.Name
    } catch { $groupNames += $dn }
  }
}
$groupsJoined = $groupNames -join ';'

function Convert-FileTime([object]$v){
  if ($null -eq $v -or $v -eq '') { return $null }
  try {
    [int64]$t=[int64]$v
    if ($t -le 0 -or $t -eq 9223372036854775807){ return $null }
    return [DateTime]::FromFileTime($t)
  } catch { return $null }
}

$auditRow = [PSCustomObject]@{
  SamAccountName    = $user.SamAccountName
  DisplayName       = $user.DisplayName
  UserPrincipalName = $user.UserPrincipalName
  Enabled           = $user.Enabled
  Department        = $user.Department
  Company           = $user.Company
  Mail              = $user.Mail
  WhenCreated       = $user.WhenCreated
  LastLogonDate     = $user.LastLogonDate
  LastLogonTS       = Convert-FileTime $user.lastLogonTimestamp
  PwdLastSet        = Convert-FileTime $user.pwdLastSet
  AccountExpires    = Convert-FileTime $user.accountExpires
  Groups            = $groupsJoined
}

$auditRow | Select-Object SamAccountName,DisplayName,UserPrincipalName,Enabled,Department,Company,Mail,WhenCreated,LastLogonDate,LastLogonTS,PwdLastSet,AccountExpires,Groups |
  Export-Csv -Path $ExportPath -NoTypeInformation -Encoding UTF8

Write-Output ("Audit export completed. File: {0}" -f $ExportPath)

⑥ 一括エクスポート:軽量監査版(列順固定)

# ADUserBulkExport_Audit.ps1
[CmdletBinding(DefaultParameterSetName='ByGroup')]
param(
  [Parameter(ParameterSetName='ByGroup', Mandatory=$true)]
  [string]$Group,
  [Parameter(ParameterSetName='ByGroup')][switch]$Recursive,
  [Parameter(ParameterSetName='ByOU', Mandatory=$true)]
  [string]$SearchBase,
  [string]$Server,
  [System.Management.Automation.PSCredential]$Credential,
  [string]$ExportFolder = "."
)

function Convert-FileTime([object]$v){
  if ($null -eq $v -or $v -eq "") { return $null }
  try {
    [int64]$t = [int64]$v
    if ($t -le 0 -or $t -eq 9223372036854775807){ return $null }
    return [DateTime]::FromFileTime($t)
  } catch { return $null }
}

$script:__cache = @{}
function Get-GroupNameFromDN([string]$dn){
  $key = "group|$dn|$Server"
  if ($__cache.ContainsKey($key)) { return $__cache[$key] }
  $p = @{ Identity=$dn; Properties='Name' }
  if ($Server)     { $p.Server     = $Server }
  if ($Credential) { $p.Credential = $Credential }
  try { $g = Get-ADGroup @p; $__cache[$key] = $g.Name; return $g.Name } catch { $__cache[$key] = $dn; return $dn }
}

Import-Module ActiveDirectory -ErrorAction Stop
$uCommon = @{ Properties = '*' }
if ($Server)     { $uCommon.Server     = $Server }
if ($Credential) { $uCommon.Credential = $Credential }

$users = @()
if ($PSCmdlet.ParameterSetName -eq 'ByGroup') {
  $gp = @{ Identity=$Group }
  if ($Server)     { $gp.Server     = $Server }
  if ($Credential) { $gp.Credential = $Credential }
  $grp = Get-ADGroup @gp

  $mp = @{ Identity=$grp.DistinguishedName }
  if ($Recursive)  { $mp.Recursive = $true }
  if ($Server)     { $mp.Server     = $Server }
  if ($Credential) { $mp.Credential = $Credential }

  $members = Get-ADGroupMember @mp | Where-Object { $_.objectClass -eq 'user' }
  foreach($m in $members) { $users += Get-ADUser @uCommon -Identity $m.DistinguishedName }
} else {
  $sp = @{ SearchBase=$SearchBase; Filter='*' }
  if ($Server)     { $sp.Server     = $Server }
  if ($Credential) { $sp.Credential = $Credential }
  $users = Get-ADUser @sp @uCommon
}

$rows = foreach($user in $users){
  $gNames = @()
  if ($user.MemberOf) {
    foreach($dn in $user.MemberOf){ $gNames += Get-GroupNameFromDN $dn }
    $gNames = $gNames | Where-Object { $_ } | Sort-Object -Unique
  }
  $groupsJoined = $gNames -join ';'

  [PSCustomObject]@{
    SamAccountName     = $user.SamAccountName
    DisplayName        = $user.DisplayName
    UserPrincipalName  = $user.UserPrincipalName
    Enabled            = $user.Enabled
    Department         = $user.Department
    Company            = $user.Company
    Mail               = $user.Mail
    WhenCreated        = $user.WhenCreated
    LastLogonDate      = $user.LastLogonDate
    LastLogonTS        = Convert-FileTime $user.lastLogonTimestamp
    PwdLastSet         = Convert-FileTime $user.pwdLastSet
    AccountExpires     = Convert-FileTime $user.accountExpires
    Groups             = $groupsJoined
  }
}

$ts   = Get-Date -Format "yyyyMMdd-HHmmss"
$name = if ($PSCmdlet.ParameterSetName -eq 'ByGroup') {
  "UserInfo_Audit_Group_$($Group -replace '[\\/:*?""<>|]','_')_${ts}.csv"
} else {
  "UserInfo_Audit_OU_${ts}.csv"
}
$path = Join-Path $ExportFolder $name

$rows | Select-Object SamAccountName,DisplayName,UserPrincipalName,Enabled,Department,Company,Mail,WhenCreated,LastLogonDate,LastLogonTS,PwdLastSet,AccountExpires,Groups |
  Export-Csv -Path $path -NoTypeInformation -Encoding UTF8

Write-Output ("Audit export completed. Rows: {0}, File: {1}" -f $rows.Count, $path)

コメント

タイトルとURLをコピーしました