通过 Powershell 更新 AD 密码

AD password update via Powershell

太多 Powershell 专家:我需要一些帮助来弄清楚为什么它工作不正常。我的意思是错误的,CSV 密码中的帐户会使用随机密码进行更新,并且会向用户发送电子邮件,但我不明白为什么他们会获得相同的密码,并且 AD 中的每个帐户都已寻址。查看电子邮件输出:

第一个用户邮箱:

Hello Guest DefaultAccount user1, user2, user3, user4 test John Doe, 
Your AD Account user1, password has been updated to e,wQlsGfBE;J'4  

第二个用户邮箱

 Hello Guest DefaultAccount user1, user2, user3, user4 test John Doe, 
Your AD Account jdoe, password has been updated to e,wQlsGfBE;J'4  

我想要完成的事情如下:

  1. 列表项
  2. 导入一列 cvs 只需 "samAccountName"
  3. 使用随机生成的 20 个字符长的密码重置 csv 中列出的帐户的密码
  4. 将新密码通过电子邮件发送给 AD 帐户关联的电子邮件地址。 (我这样做是因为他们的电子邮件地址与他们的 AD 帐户不同),所以他们能够收到他们的电子邮件。

Import-Module ActiveDirectory
# Import AD user objects and store in users variables 
$users = Get-ADUser -Filter *  -Properties Name, EmailAddress,SamAccountName | Select SamAccountName,Name,EmailAddress
    
$Name = $users.Name
$SamAccountName = $users.SamAccountName
$EmailAddress = $users.EmailAddress

#Date
$date = (Get-Date -Format F) 

#Generate a random password and store in newpwd 
$newpwd = -join (33..126|%{[char]$_}|Get-Random -Count 20)
$newPassword = ConvertTo-SecureString -AsPlainText "$newpwd" -Force

# Import users from CSV
Import-Csv "C:\Userlist.csv" | ForEach-Object {
$samAccountName= $_."samAccountName"

        #Proceed with password reset
            Set-ADAccountPassword -Identity $samAccountName -NewPassword $newPassword -Reset
            Set-AdUser -Identity $samAccountName -ChangePasswordAtLogon $true

#Server configuration 
$smtpServer =""
$SmtpPort = ""
# sending option
$from = "it-operation@example.com"
$to = $EmailAddress 
$subject  ="AD Password updated - " + $date
$priority = "Normal"
$from = ""

$body = @"
Hello $name, <br> 
Your AD Account $samAccountName, password has been updated to $newpwd
"@
try {
# Send the report email
Send-MailMessage -To $to -Subject $subject -BodyAsHtml -body $body -SmtpServer $smtpServer -Port $SmtpPort -From $From -Priority $priority  
}
catch{
    write-warning "error in sending. $_"
}  # End User Processing
            
    }

正在更新帐号密码,但无法发送邮件

当您执行 $Name = $users.Name 时,$Name 变量会得到一个包含 ALL 个 CSV 用户名的数组。

删除该行,而是在 ForEach-Object 循环中设置变量:

# Import users from CSV
$UserList = Import-Csv "C:\Userlist.csv" | ForEach-Object {
    $samAccountName= $_.samAccountName
    $name = $_.Name
    # then the rest of your code
}

注:

  • SmtpPort 采用整数,而不是字符串
  • From 不能为空字符串

P.S。尝试做一些适当的代码缩进,这样更容易看到代码块(如 ForEach-Object)的开始和结束)


您的代码已修改:

Import-Module ActiveDirectory
# Import AD user objects and store in users variables 
$users = Get-ADUser -Filter *  -Properties Name, EmailAddress,SamAccountName | Select SamAccountName,Name,EmailAddress

#Date
$date = (Get-Date -Format F) 

# Import users from CSV
Import-Csv "C:\Userlist.csv" | ForEach-Object {
    # read this from the CSV
    $samAccountName= $_.samAccountName
    # get the user object from the $users array
    $user = $users | Where-Object { $_.SamAccountName -eq $samAccountName }
    $name = $user.Name
    $emailAddress = $user.EmailAddress

    #Generate a random password and store in newpwd 
    $newpwd = -join (33..126|%{[char]$_}|Get-Random -Count 14)
    $newPassword = ConvertTo-SecureString -AsPlainText "$newpwd" -Force

    $body = @"
Hello $name, <br> 
Your AD Account $samAccountName, password has been updated to $newpwd
"@

    #Proceed with password reset
    Set-ADAccountPassword -Identity $samAccountName -NewPassword $newPassword -Reset
    Set-AdUser -Identity $samAccountName -ChangePasswordAtLogon $true

    #Server configuration 
    $mailParams = @{
        SmtpServer = "YourSMTPServer"
        Port = 25  # <-- an integer value
        # sending option
        From = "it-operation@example.com"
        To = $user.EmailAddress 
        Subject  ="AD Password updated - " + $date
        Priority = "Normal"
        Body = $body
        BodyAsHtml = $true
    }
    try {
    # Send the report email
    Send-MailMessage @mailParams -ErrorAction Stop
    }
    catch{
        write-warning "error in sending. $_"
    }  # End User Processing
}

不要接受我的回答。我只是在构建@Theo 所做的事情。 (虽然我喜欢投票)

Import-Module ActiveDirectory

# Import AD user objects and store in users variables 
$Users = @{} 
Get-ADUser -Filter *  -Properties Name,EmailAddress,SamAccountName | Select-Object SamAccountName,Name,EmailAddress |
ForEach-Object{ $Users.Add( $_.samAccountName, $_ ) }

#Date
$Date = (Get-Date -Format F) 

# Generate a random password and store in newPassword 
$newPassword = -join ( 33..126 | ForEach-Object{ [char]$_ }| Get-Random -Count 20 )
$newPassword = ConvertTo-SecureString -AsPlainText "$newPassword" -Force
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Move to the loop if you want each user's pwd to be different!!!

# Put this here so you can indent the loop easier...
$BaseBody = 
@"
Hello %NAME%, <br> 
Your AD Account %SAMACCOUNTNAME%, password has been updated to %NEWPASSWORD%
"@

# Server configuration & recipien configurations...:
$MailParams = @{
    $smtpServer = "YorServer.example.com" #MAKE SURE YOU CHANGE THIS
    $SmtpPort   = 25
    $from       = "it-operation@example.com"
    $To         = ""
    $subject    ="AD Password updated - " + $date
    $Body       = ""
}
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Removed -Priority if it's alwasy going to be normal you don't need it.

# Import users from CSV
Import-Csv "C:\Userlist.csv" | 
ForEach-Object {
    $samAccountName = $_."samAccountName"

    # Proceed with password reset
    Set-ADAccountPassword -Identity $samAccountName -NewPassword $newPassword -Reset
    Set-ADUser -Identity $samAccountName -ChangePasswordAtLogon $true

    # Get the Name & Email address from the $Users Hash...:
    $EmailAddress = $Users[$samAccountName].EmailAddress
    $Name         = $Users[$samAccountName].Name

    # Reset the To & Body values
    $MailParams['To']   = $EmailAddress
    $MailParams['Body'] = $BaseBody.Replace('%NAME%', $Name).Replace('%SAMACCOUNTNAME%', $samAccountName).Replace('%NEWPASSWORD%', $newPassword)    

    try { # Send the report email
        Send-MailMessage @MailParams -ErrorAction Stop
    }
    catch{
        write-warning "Error in sending : $_"
    }
} # End User Processing
  • 使用散列 table 存储 AD 用户对象,因此您不必在每次循环迭代时重新执行 Where{}。根据用户数量,这可能会快很多。在 2 个来源之间关联数据时,我倾向于哈希 tables.
  • 将 $Body 变量移出循环。这里的字符串不喜欢缩进,通过将其移出我们不必干扰循环缩进;提高可读性。然后在循环中我们可以通过一些字符串替换来获取实际的主体。
  • 我还将 $MailParams 参数散列放在循环之外。然后在循环内我重置了 2 个不同的键。吹毛求疵,但我也不想在每次循环迭代时都声明散列。
  • $重用了 $newPassword 变量,而不是随意使用额外的 $newpdw 变量。
  • 扩展了别名,只是因为 PSScriptAnalyzer 抱怨它...

显然这是未经测试的!但是,我希望它能有所帮助...