Add User Active Directory with password and compare with AD Password Complexity - powershell

I'm trying to use a script to create User account on my AD.(Newbie)
I use this kind of powershell code:
Import-Module ActiveDirectory
#Intro
$date = Get-Date -Format "dd-MM-yyyy"
Echo "The $date - Adding new user"
#GET NAME and SURNAME :
$name = Read-Host "Enter the NAME of the user, please ?"
$surname = Read-Host "Enter the SURNAME of the user, please?"
#Username
$login = ($surname).Substring(0, 1).ToLower() + $name.Substring(0, 2).ToLower()
#Password requirement
Write-Verbose -Message "The password must contains : 8 char. with 1 maj. , 1 min. et 1 number or 1 char special." -Verbose
$password = Read-Host "Enter the password"
#Verify login does not exist
Echo "Wait a seconds..."
if (Get-ADUser -Filter { SamAccountName -eq $login }) {
Write-Warning "User Already Exist! please Try again..."
.\new_user.ps1
}
else {
#User Creation With File Folder
try {
New-ADUser -Name "$name $surname" -GivenName $name -Surname $surname -SamAccountName $login -UserPrincipalName $login#contonso.com -AccountPassword (ConvertTo-SecureString -AsPlainText $password -Force) -PasswordNeverExpires $true -CannotChangePassword $True -Enabled $true -path “OU=User, DC=Contonso, DC=com”
Write-Verbose -Message "The user account $login has been created and is active. Send an email with these credential" -Verbose
}
catch {
$_ | Out-File -FilePath C:\LOGS\EU-$login-$date.txt
Write-Warning "Sorry. An error as occured creating the user account. Thanks to try again."
}
try {
New-Item -Path \\FILESERVER\D$\Share\4.Users -Name "$login" -ItemType Directory
Write-Verbose -Message "The file folder of $login is now available." -Verbose
}
catch {
$_ | Out-File -FilePath C:\LOGS\ER-$login-$date.txt
Write-Warning "Sorry. An error as occurred while creating the folder, please contact the IT Team.Thanks"
}
}
If i put example "apple" as a password, the code will continue creating the account with the password but the account is disable and on my log i will have "Password does not fit with Active Directory complexity (set on GPO).
So i know there is a cmd: "Get-ADDefaultDomainPasswordPolicy" how to use it to compare my password with this ?
I found some function on internet but they use password policy directly on the powershell script.
In my case i want to compare directly with the ADDefaultDomainPassword Policy.
Any Idea? Thanks a lot

To test if a password would pass the complexity rules, you can use below function:
function Test-DomainPassword {
# see: https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/password-must-meet-complexity-requirements
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[ValidateNotNullOrEmpty()]
[string]$Password,
[string]$SamAccountName = $null,
[string]$DisplayName = $null
)
$PasswordPolicy = Get-ADDefaultDomainPasswordPolicy -ErrorAction SilentlyContinue
if ($Password.Length -lt $PasswordPolicy.MinPasswordLength) {
Write-Verbose "Password '$Password' is too short. Minimal length is $($PasswordPolicy.MinPasswordLength)"
return $false
}
if (($SamAccountName) -and ($Password -match [regex]::Escape($SamAccountName))) {
Write-Verbose "The password '$Password' includes the users SamAccountName"
return $false
}
if ($DisplayName) {
# The displayName is parsed for delimiters: commas, periods, dashes or hyphens, underscores, spaces, pound signs, and tabs.
# If any of these delimiters are found, the displayName is split and all parsed sections (tokens) are confirmed not to be
# included in the password.
# Tokens that are shorter than three characters are ignored, and substrings of the tokens aren't checked.
$tokens = $DisplayName -split '[-,._ #\t]'
foreach ($token in $tokens) {
if (($token) -and ($token.Length -ge 3) -and ($Password -match [regex]::Escape($token))) {
Write-Verbose "The password '$Password' includes (part of) the users DisplayName"
return $false
}
}
}
if ($PasswordPolicy.ComplexityEnabled) {
# see: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/bb726984(v=technet.10)?redirectedfrom=MSDN
# chapter 'Passwords Must Meet Complexity Requirements':
# Passwords must use three of the four available character types:
# lowercase letters, uppercase letters, numbers, and symbols.
$failures = #()
# check for presence of
# - Uppercase: A through Z, with diacritic marks, Greek and Cyrillic characters
if ($Password -cnotmatch "[A-Z\p{Lu}\s]") {
$failures += "- The password is missing Uppercase characters"
}
# - Lowercase: a through z, sharp-s, with diacritic marks, Greek and Cyrillic characters
if ($Password -cnotmatch "[a-z\p{Ll}\s]") {
$failures += "- The password is missing Lowercase characters"
}
# - Base 10 digits (0 through 9)
if ($Password -notmatch "[\d]") {
$failures += "- The password is missing digits (0-9)"
}
# - Nonalphanumeric characters: ~!##$%^&*_-+=`|\(){}[]:;"'<>,.?/
if ($Password -notmatch "[^\w]") {
$failures += "- The password is missing Nonalphanumeric characters: ~!##$%^&*_-+=`|\(){}[]:;`"'<>,.?/"
}
# test if we have more than 1 mismatch (password needs at least 3 out of 4 to be OK)
if ($failures.Count -gt 1) {
Write-Verbose "The password '$Password' failed because:`r`n{0}" -f ($failures -join "`r`n")
return $false
}
}
$true
}
Use it like this:
# both parameters -SamAccountName and -DisplayName are optional
$displayName = '{0} {1}' -f $firstname, $surname
if (Test-DomainPassword -Password $password -SamAccountName $login -DisplayName $displayName -Verbose) {
# the password is OK, create the new user here:
$userParams = #{
SamAccountName = $login
GivenName = $firstname
Surname = $surname
DisplayName = $displayName
UserPrincipalName = '{0}#contonso.com'-f $login
AccountPassword = ConvertTo-SecureString -String $password -AsPlainText -force
PasswordNeverExpires = $true
CannotChangePassword = $true
Path = 'OU=User,DC=Contonso,DC=com'
Enabled = $true
# etcetera
}
New-ADUser #userParams
}
else {
Write-Warning "User $login NOT created because the password did not pass the test"
}

Related

How to create samaccountname with maximum 12 character?

I need to create users with max 12 characters.
The last name can contain the first 11 characters (max) + the first letter of the first name
I'm not sure what to add next to $LastName
Can you help me with this?
$OU = "OU=Users,DC=domain,DC=com"
$PW = "Welcome$(Get-Random -minimum 0001 -maximum 9999)!"
$FirstName = Read-Host "Please enter the Firstname for the new user"
$LastName = Read-Host "Please enter the Lastname for the new user"
$AccountName = $LastName + $FirstName[0] # Last name (11 caracter max) + first character of first name
# test if a user with that accountname already exists and if so, append a sequence number
$count = 1
while (Get-ADUser -Filter "SamAccountName -eq '$AccountName'") {
$AccountName = '{0}{1}{2}' -f $LastName, $FirstName[0], $count++
}
$UPN = "$($FirstName).$($LastName)#domain.com" #if the upn exists, add a digit to the last name
# test if a user with that UserPrincipalName already exists and if so, append a sequence number
$count = 1
while (Get-ADUser -Filter "UserPrincipalName -eq '$UPN'") {
$UPN = '{0}.{1}{2}#domain.com' -f $FirstName, $LastName, $count++
}
# create a Hashtable for splatting parameters
$userParams = #{
Name = "$($LastName), $($FirstName)"
DisplayName = "$($LastName), $($FirstName)"
FirstName = $FirstName
LastName = $LastName
SamAccountName = $AccountName
OnPremisesOrganizationalUnit = $OU
UserPrincipalName = $UPN
Password = $PW | ConvertTo-SecureString -AsPlainText -Force
ResetPasswordOnNextLogon = $true
Archive = $true
}
# Create User On-Premise and move to the managers OU if possible
try {
New-RemoteMailbox #userParams -ErrorAction Stop
}
catch {
Write-Error $_.Exception.Message
}

AD-user script has no output

I'm creating a script for adding multiple users in Active Directory. I stumbled upon this link, when I couldn't get the guide described in the question to work either. I then tried one of the solutions in the comments
Import-Module ActiveDirectory
# this defaults to csv fields delimited by a comma. If your CSV file uses a different
# character, then add parameter '-Delimiter' followed by the actual character
$ADUsers = Import-Csv -Path 'C:\Users\Desktop\Powershell files\EM-mis-new-AD.csv'
# the Where-Object clause is just a precaution to omit records that have no username value
$ADUsers | Where-Object { $_.username -match '\S'} | ForEach-Object {
$Username = $_.username
if (Get-ADUser -Filter "SamAccountName -eq '$Username'" -ErrorAction SilentlyContinue) {
Write-Warning "A user account with SamAccountName '$Username' already exist in Active Directory."
}
else {
$Firstname = $_.firstname
$Lastname = $_.lastname
# use splatting on cmdlets that use a lot of parameters
$userParams = #{
SamAccountName = $Username
UserPrincipalName = "$Username#Mydomain.com"
Name = "$Firstname $Lastname"
GivenName = $Firstname
Surname = $Lastname
Enabled = $true
DisplayName = "$Firstname, $Lastname"
Path = $_.ou
AccountPassword = (ConvertTo-SecureString $_.Password -AsPlainText -Force)
ChangePasswordAtLogon = $true
}
# create the user and report back
New-ADUser #userParams
Write-Host "Created new user '$Username' with initial password: $($_.Password)"
}
}
Here is my CSV file
firstname;lastname;username;password;ou
Mette;Frederiksen;MeFr;Password1;OU=Salg,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Sussi;Hart;SuHa;Password1;OU=Salg,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Ove;Tylstrup;OvTy;Password1;OU=Salg,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Karlos;Mondolez;KaMo;Password1;OU=Lager,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Anne;Otto;AnOt;Password1;OU=Lager,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Dennis;Ågard;DeÅg;Password1;OU=Lager,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Helena;Riss;HeRi;Password1;OU=Okonomi,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
Risa;Lamende;RiLa;Password1;OU=Okonomi,OU=Users,OU=RGD Aarhus,DC=rgd,DC=local
However, when I run the above code nothing happens
PS C:\Users\RGDAdmin> C:\Users\RGDAdmin\Documents\ADUser.ps1
PS C:\Users\RGDAdmin>
When I add the Delimiter parameter, I get this
Created new user 'KaMo' with initial password: Password1
New-ADUser : The directory service was unable to allocate a relative identifier
At C:\Users\RGDAdmin\Documents\ADUser.ps1:31 char:9
+ New-ADUser #userParams
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (CN=Anne Otto,OU...DC=rgd,DC=local:String) [New-ADUser], ADException
+ FullyQualifiedErrorId :
ActiveDirectoryServer:8208,Microsoft.ActiveDirectory.Management.Commands.NewADUser
PS. I know the password is bad practice in terms of passwords
Your file is delimited by semicolons, so you will definitely need to specify the -Delimiter parameter. But the documentation has a caveat:
To specify a semicolon (;) enclose it in single quotation marks.
So it should look like this:
$ADUsers = Import-Csv -Delimiter ';' -Path 'C:\Users\Desktop\Powershell files\EM-mis-new-AD.csv'
If that still results in that RID error, then there's possibly something wrong on the server. Can you create users manually using AD Users and Computers?
Try reviewing this. I don't have access to ActiveDirectory to test it myself.
#helpers
function usernameIsNotBlank {
[CmdletBinding()]
param(
$Username
)
[regex]$rx = "\S"
return $rx.match($Username)
}
function usernameDoesNotAlreadyExist {
[CmdletBinding()]
param(
$Username
)
$UserDoesNotExist = $true
$UserObject = $(
try {
Get-ADUser $Username
}
catch {
$null
}
)
if ($null -ne $UserObject) {
$UserDoesNotExist = $false
Write-Verbose "$Username already exists"
}
else {
$UserDoesNotExist = $true
}
return $UserDoesNotExist
}
function suppliedUsernameIsAvailable {
[CmdletBinding()]
param(
$Username
)
return ((usernameIsNotBlank -Username $Username) -and (usernameDoesNotAlreadyExist -Username $Username))
}
#script
$OriginalVerbose = $VerbosePreference
$VerbosePreference = "Continue"
Import-Module ActiveDirectory
$CSV = "C:\Users\Desktop\Powershell file\EM-mis-new-AD.csv"
$Data = Import-CSV $CSV
foreach ($Line in $Data) {
if (suppliedUsernameIsAvailable($Line.username)) {
New-ADUser -Name "$Line.firstname $Line.lastname" -GivenName "$Line.firstname" -Surname "$Line.lastname" -SamAccoutnname "$(Line.username)#mydomain.com" -AccountPassword (ConvertTo-SecureString $Line.password -AsPlainText -Force) -ChangePasswordAtLogon $true -Path "$Line.ou"
}
}
$VerbosePreference = $OriginalVerbose

ADuser not adding samAccountName after changing Variable

Thanks in advance !
I have made a script and in this script, I add users from excel to AD and it works for 99% but I need to make 1 change to it but when I do that it gives me errors.
Import-Csv -Path C:\Users\admin.kln\Documents\Project\BOSAN_USERS.csv |foreach{
#All strings of variables you need out of excel
$Firstname = $_.Firstname
$Lastname = $_."Last Name"
$Displayname = $_."Display Name"
$Extraname = $_."Display Name"
$Logonname = $_."Logon Name"
$Accountpassword = $_.AccountPassword
$Description = $_.Description
$Jobtitle = $_."Job Title"
$Department = $_.Department
$Company = $_.Company
$Telephonenumber = $_.TelephoneNumber
$Mobilenumber = $_."Mobile number"
$Street = $_.Street
$PObox = $_."P.O. Box"
$City = $_.City
$State = $_."State / Province"
$Zip = $_.Zip
$Country = $_.Country
$Manager = $_.Manager
$ProxyEmail = $_."Proxy Address + Email(SMTP)"
$ProxyAdress = $_."Proxy Addresss(smpt)"
$ProxySip = $_."Proxy address (SIP)"
$Final = (($_.Firstname.ToLower().Substring(0,1)) + '.' + ($_."Last name".ToLower()))
#int
$i = 1
$u = 1
$o = 1
#Check if its over 18 chars if it is it will be shortened
if ($Displayname.Length -gt 18) { $Displayname = $Displayname.Substring(0,18) }
if ($Extraname.Length -gt 18) { $Extraname = $Extraname.Substring(0,18) }
try
{
while (Get-ADUser -F {SamAccountName -eq $Extraname})
{
Write-Warning "Er bestaat al een account met de naam $Extraname"
$Extraname = $Displayname + [string]$i
$i++
$Logonname = $Logonname + [string]$o
$o++
$Final = (($_.Firstname.ToLower().Substring(0,1)) + '.' + ($_."Last Name".ToLower()))
$Final = $Final + [string]$u
$u++
}
}
catch{}
finally
{
$Logonname = $Logonname -replace ' ',''
$Final = $Final -replace ' ',''
echo $Final
New-ADUser -Path "ou=Users,ou=NLHKH,dc=CONTOSO,dc=com" `
-SamAccountName $Extraname `
-GivenName $Firstname `
-Name $Extraname `
-Surname $Lastname `
-DisplayName $Extraname `
-UserPrincipalName $Final `
-accountpassword(ConvertTo-SecureString "Password1" -AsPlainText -force) `
-ChangePasswordAtLogon $true `
-Description $Description `
-Title $Jobtitle `
-Department $Department `
-Company $Company `
-MobilePhone $Mobilenumber `
-StreetAddress $Street `
-City $City `
-State $State `
-PostalCode $Zip `
-POBOX $PObox
}
}
As you can see it should work like this but I need to change -SamAccountName to $final or at least to the same Variable as $Final. But that won't do.
Personally, I would change quite a lot of your script.
First of all, you need two loops to figure out if
you get a valid unique SamAccountName
you get a valid unique UserPrincipalName
The ProxyAddresses need extra care aswell. You need to create an array of the 3 Proxy* fields in the CSV and add that with parameter OtherAttributes.
Mind that his will not accept a 'normal' array and that it needs to be cast with [string[]] to form a strongly typed string array.
Finally, use Splatting for the New-ADUser cmdlet to get rid of those nasty backticks.
Something like this:
Import-Csv -Path 'C:\Users\admin.kln\Documents\Project\BOSAN_USERS.csv' | ForEach-Object {
# unused fields in the CSV:
# $Logonname = $_."Logon Name"
# $Country = $_.Country
# $Manager = $_.Manager
# construct a SamAccountName from the DisplayName in the CSV
# replace all invalid characters and cut off anything over 20 characters
$SamAccountName = $_."Display Name" -replace '[\x00-\x20"[\]:;|=+*?<>/,#\s]'
if ($SamAccountName.Length -gt 20) { $SamAccountName = $SamAccountName.Substring(0, 20) }
$temp = $SamAccountName
# enter an endless loop to test if that user with that SamAccountName already exists
$i = 1
while ($true) {
$user = Get-ADUser -Filter "SamAccountName -eq '$SamAccountName'" -ErrorAction SilentlyContinue
# if a user with that SamAccountName does not yet exist, we can break out of the loop
if (!$user) { break }
# create a new SamAccountName to test
while (($temp + $i).Length -gt 20) {
$temp = $temp.Substring(0, $temp.Length - 1)
}
$SamAccountName = '{0}{1}' -f $temp, $i
$i++
}
# since your UPN uses a different format than 'SamAccountName#CONTOSO.com',
# start another loop to make sure that too is unique
# CHANGE #CONTOSO.com TO THE REAL DOMAIN NAME
$UserPrincipalName = '{0}.{1}#CONTOSO.com' -f $_.Firstname.Substring(0,1).ToLower(), $_."Last name".ToLower()
$i = 1
while ($true) {
$user = Get-ADUser -Filter "UserPrincipalName -eq '$UserPrincipalName'" -ErrorAction SilentlyContinue
# if a user with that UserPrincipalName does not yet exist, we can break out of the loop
if (!$user) { break }
# create a new UserPrincipalName by adding a sequence number to test
$UserPrincipalName = '{0}.{1}{2}#CONTOSO.com' -f $_.Firstname.Substring(0,1).ToLower(), $_."Last name".ToLower(), $i
$i++
}
# next, create an array of the Proxy Addresses. Watch the spelling in the CSV headers!
$ProxyAddresses = ('SMTP:{0}' -f ($_."Proxy Address + Email(SMTP)" -replace '^SMTP:')),
('smtp:{0}' -f ($_."Proxy Address(smpt)" -replace '^smtp:')),
('SIP:{0}' -f ($_."Proxy address (SIP)" -replace '^SIP:'))
# now that we have unique names and a ProxyAddresses array, we can create the user
$NewUserParms = #{
'SamAccountName' = $SamAccountName
'Name' = ('{0} {1}' -f $_.FirstName, $_."Last Name").Trim()
'DisplayName' = $_."Display Name"
'UserPrincipalName' = $UserPrincipalName
'GivenName' = $_.FirstName
'Surname' = $_."Last Name"
'Description' = $_.Description
'Title' = $_."Job Title"
'Department' = $_.Department
'Company' = $_.Company
'AccountPassword' = ConvertTo-SecureString $_.AccountPassword -AsPlainText -Force
'ChangePasswordAtLogon' = $true
'Enabled' = $true
'OfficePhone' = $_.TelephoneNumber
'MobilePhone' = $_."Mobile number"
'StreetAddress' = $_.Street
'City' = $_.City
'State' = $_."State / Province"
'PostalCode' = $_.Zip
'POBox' = $_."P.O. Box"
'EmailAddress' = $_."Proxy Address + Email(SMTP)" -replace '^SMTP:'
'Path' = "OU=Users,OU=NLHKH,DC=CONTOSO,DC=com"
# ProxyAddresses needs cast to [string[]]
'OtherAttributes' = #{'proxyAddresses' = [string[]]$ProxyAddresses}
# add other properties to set from the CSV here if needed.
# make sure you get the parameter data types correct and always check here:
# https://learn.microsoft.com/en-us/powershell/module/addsadministration/new-aduser?view=win10-ps#parameters
# switch parameters for the cmdlet can also be entered with a value $false or $true
}
try {
# '-ErrorAction Stop' ensures that also non-terminating errors get handled in the catch block
New-ADUser #NewUserParms -ErrorAction Stop
}
catch {
# something bad happened. Change 'Write-Warning' into 'throw' if you want your script to exit here
# inside a catch block, the '$_' automatic variable represents the actual exception object.
Write-Warning "Could not create account $username. $($_.Exception.Message)"
}
}

Send email to AD users when their password is about to expire

I've been working on a PowerShell script that sends an automated email out to AD users when their password is about to expire. My script has a ForEach statement in it but nothing within this actually runs. I've set it up so that it logs all activities in a .txt file so I can see when each step is being worked on. It's running on a Windows 2016 Essentials.
Script Below:
# VAR
$SMTPHost = "smtp.office365.com"
$FromEmail = "***"
$expireindays = 3
$Date = Get-Date
# Set DIR
$DirPath = "C:\TEMP"
# Check is DIR is present
$DirPathCheck = Test-Path -Path $DirPath
if (!($DirPathCheck)) {
try {
#Create DIR if not present
New-Item -ItemType Directory $DirPath -Force
}
catch {
$_ | Out-File ($DirPath + "\" + "Log.txt") -Append
}
}
# CredObj
$CredObj = ($DirPath + "\" + "EmailExpiry.cred")
# Check if CredObj is Present
$CredObjCheck = Test-Path -Path $CredObj
If (!($CredObjCheck))
{
"$Date - INFO: creating cred object" | Out-File ($DirPath + "\" + "Log.txt") -Append
#If not present get O365 cred and store
$Credential = Get-Credential -Message "Please enter your Office 365 credentials."
#Export CredObj
$Credential | Export-Clixml -Path $CredObj
}
Write-Host "INFO | Importing Cred Object" -ForegroundColor Yellow
$Cred = (Import-Clixml -Path $CredObj)
"$Date - INFO: Importing AD Module" | Out-File ($DirPath + "\" + "Log.txt") -Append
Import-Module ActiveDirectory
"$Date - INFO: Getting Users" | Out-File ($DirPath + "\" + "Log.txt") -Append
Write-Host "INFO | Getting Users" -ForegroundColor Yellow
$users = Get-ADUser -properties Name, PasswordExpired, PasswordLastSet, EmailAddress -filter { (enabled -eq 'True') } | Where-Object { $_.PasswordExpired -eq 'False'}
# Process Each User for Password Expiry
ForEach ($User in $Users) {
$Name = (Get-ADUser $user | Get-ADUser -Property Name)
Write-Host "Working on $Name..." -ForegroundColor White
Write-Host "Getting email address for $Name..." -ForegroundColor Yellow
$emailaddress = $user.EmailAddress
if (!($emailaddress)) {
Write-Host "$Name has no E-Mail address listed, looking at their proxy address attributes..."
if (!($emailaddress)) {
Write-Host "$Name has no email address to send an e-mail to!" -ForegroundColor Red
"$Date - WARNING: No email found for $Name" | Out-File ($DirPath + "\" + "Log.txt") -Append
}
}
#Get password last set
$passwordSetDate = (Get-AAUser $user -properties * | ForEach-Object { $_.PasswordLastSet})
#Get the count on how many days until the password expires and stores it in the $daystoexpire VAR
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
if (($daystoexpire -ge "0") -and ($daystoexpire -lt $expireindays)) {
"$Date - INFO: Sending expiry notice email to $Name" | Out-File ($DirPath + "\" + "Log.txt")
Write-Host "Sending Password expiry email to $Name" -ForegroundColor Yellow
$SmtpClient = New-Object system.net.mail.smtpclient
$MailMessage = New-Object system.net.mail.mailmessage
#Email Sender
$MailMessage.From = $FromEmail
#SMTP Server
$SmtpClient.Host = $SMTPHost
#SMTP SSL
$SmtpClient.EnableSsl = $true
#SMTP Credentials
$SmtpClient.Credentials = $Cred
#Email Recipients
$MailMessage.To.add($emailaddress)
#Subject
$MailMessage.Subject = "Your password will expire $daystoexpire days"
#Delivery Success
$MailMessage.DeliveryNotificationOptions = ("onSuccess", "onFailure")
#Set Priority
$MailMessage.Priority = "High"
#Body
$MailMessage.Body = "Password will expire, better change it!"
Write-Host "Sending email to $emailaddress..." -ForegroundColor Green
try {
$SmtpClient.Send($MailMessage)
}
catch {
$_ | Out-File ($DirPath + "\" + "Log.txt") -Append
}
else {
"$Date- INFO: Password for $Name not expiring for another $daystoexpire days" | Out-File ($DirPath + "\" + "Log.txt") -Append
Write-Host "Password for $Name does not expire for $daystoexpire days" -ForegroundColor White
}
}
}
Output:
I noticed you did not set the $Expireson variable anywhere, so you would not get a correct value for $daystoexpire aswell.
As a matter of fact, I made a script to do the same some time ago. I have edited it a bit for you to try out.
This uses the Send-Mailmessage instead of the System.Net.Mail.SmtpClient to make things easier. This way, we can also use Splatting to make the code more readable.
Import-Module ActiveDirectory
$smtpServer = "smtp.office365.com"
$expireInDays = 3 # 3 is a bit close... better do something like 7
$from = "YOUR EMAILADDRESS"
$logPath = "C:\TEMP"
$logFile = Join-Path -Path $logPath -ChildPath 'PasswordExpiryLog.txt'
$logDate = '{0:dd-MM-yyyy}' -f (Get-Date)
$credPath = Join-Path -Path $logPath -ChildPath 'EmailExpiry.cred'
# create the output path if it does not exist
if (!(Test-Path -Path $logPath -PathType Container)) {
New-Item -Path $logPath -ItemType Directory | Out-Null
}
# Credentials
If (!(Test-Path -Path $credPath -PathType Leaf)) {
# write to the log and screen
$msg = "Creating credentials object"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
# If not present get O365 cred and store
$cred = Get-Credential -Message "Please enter your Office 365 credentials."
# Export CredObj
$cred | Export-Clixml -Path $credPath
}
else {
# write to the log and screen
$msg = "Importing credentials Object"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
$cred = Import-Clixml -Path $credPath
}
# create a template for the emails
$emailTemplate = #"
<html>
<head>
<title>Password Expire Notification</title>
<meta name="generator" content="PowerShell" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 12px;
}
</style>
</head>
<body>
Dear _NAME_,
<p>Your password will expire in _DAYS_ days.<br /><br />
To change your password on a Windows pc in the office press CTRL-ALT-Delete and choose <strong>Change a password...</strong><br />
</p>
Regards
</body>
</html>
"#
# get all users that are enabled and that have a password expiry date
# test it out on dummy user(s) first of course !
$users = Get-ADUser -Filter * -Properties GivenName, Name, SamAccountName, PasswordNeverExpires, PasswordExpired,
PasswordLastSet, EmailAddress, AccountExpirationDate, accountExpires |
Where-Object { $_.Enabled -eq $true -and $_.PasswordNeverExpires -eq $false}
# get the domains default max password age
$defaultMaxPasswordAge = (Get-ADDefaultDomainpasswordPolicy).MaxPasswordAge
$mailCount = 0
foreach ($user in $users) {
if ([string]::IsNullOrWhiteSpace($emailAddress)) {
# write to the log and screen
$msg = "$userName has no email address to send an e-mail to!"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
# skip this user because we cannot send mail..
continue
}
# just for convenience, store some properties in variables
$firstName = $user.GivenName
$userName = $user.Name
$accountName = $user.SamAccountName
$emailAddress = $user.EmailAddress
$passwordSetDate = $user.PasswordLastSet
$passwordPolicy = (Get-AduserResultantpasswordPolicy $user)
# check if there is a 'Fine Grained Password' policy for this user
if ($null -ne $passwordPolicy) {
$maxPasswordAge = ($passwordPolicy).MaxPasswordAge
}
else {
# no 'Fine Grained Password' policy, so use the default domain password age
$maxPasswordAge = $defaultMaxPasswordAge
}
# prevent errors when the 'User must change password at next logon' checkmark is set
if (!$passwordSetDate -or !$maxPasswordAge) {
# write to the log and screen
$msg = "Please check if the 'User must change password at next logon' checkmark is off for user '$userName'"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
}
# calculate the expiry date for the password
$passwordExpiresAt = $passwordSetDate + $maxPasswordAge
# check if the account does not expire before the password does using the accountExpires property.
# 0 means the expiration date has been removed. 9223372036854775807 means the account never had an expiration date
if ($user.accountExpires -ne 0 -and $user.accountExpires -ne 9223372036854775807 -and $user.AccountExpirationDate -ne $null) {
if ($user.AccountExpirationDate -le $passwordExpiresAt) {
# skip this user if the account expires before the password needs changing
$msg = "The account for user '$userName' expires before the password needs changing."
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
continue
}
}
# calculate how many days are left
$daysToExpire = [int](New-TimeSpan -Start (Get-Date) -End $passwordExpiresAt).Days
if (($daysToExpire -ge 0) -and ($daysToExpire -lt $expireInDays)) {
# if there are still days left to change the password, send an email
# using Send-MailMessage rather than System.Net.Mail.SmtpClient
$msg = "Sending expiry notice email to '$userName'"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
# use splatting for cmdlets that take a lot of parameters
$params = #{
SmtpServer = $smtpServer
From = $from
To = $emailAddress
Subject = "Your password will expire in $daysToExpire days."
Body = $emailTemplate -replace "_NAME_", $firstName -replace "_DAYS_", $daysToExpire
BodyAsHtml = $true
Encoding = [System.Text.Encoding]::UTF8
Credential = $cred
UseSsl = $true
Priority = 'High'
DeliveryNotificationOption = 'OnSuccess', 'OnFailure'
# Port = 587
}
Send-Mailmessage #params
# update the counter for the users that were sent an email
$mailCount++
}
elseif ($daysToExpire -le 0) {
$msg = "Password for user '$userName' is already expired!"
Add-Content -Path $logFile -Value "$logDate - WARNING: $msg"
Write-Host $msg -ForegroundColor Red
}
}
$msg = "Password expiry notifications have been sent to $mailCount users"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Green
Note: As always, create a couple of testusers to try this out first. You can use the -Filter parameter on the Get-ADUser cmdlet to only get the testuser or use the -SearchBase parameter and put your test accounts in a special OU.

I want to add a random generated password to my newly created Active Directory User

I want to add a randomly generated password to my newly created Active Directory User. I have written a function to generate the password. I am using Powershell V2.0
I tried the below but did not help.
Import-Module ActiveDirectory
[xml]$dataSource = Get-Content C:\Names1.xml
$name = Read-Host 'Please enter the table name : '
$user_logon = $dataSource.names.$name | ? { $_.Rule_Label -eq 'Regular service account (user logon)'}
$display_name = $dataSource.names.$name | ? { $_.Rule_Label -eq 'Regular service account (display name)'}
$pre_windows = $dataSource.names.$name | ? { $_.Rule_Label -eq 'Regular service account (pre-Windows 2000)'}
Function GET-Temppassword() {
Param(
[int]$length=10,
[string[]]$sourcedata
)
For ($loop=1; $loop –le $length; $loop++) {
$TempPassword+=($sourcedata | GET-RANDOM)
}
return $TempPassword
}
switch ($name)
{
DevTable{foreach($dataRecord in $dataSource)
{
try
{
$cn=$user_logon.Output_Value
$sAMAccountName=$user_logon.Output_Value
$givenName=$user_logon.Output_Value
$sn=$user_logon.Output_Value
$displayName=$display_name.Output_Value
$userPrincipalName=$sAMAccountName + “#test.com”;
$alphabet=$NULL;For ($a=65;$a –le 90;$a++) {$alphabet+=,[char][byte]$a }
$TempPassword1 = GET-Temppassword –length 10 –sourcedata $alphabet
New-ADUser $cn -SamAccountName $sAMAccountName -GivenName $givenName -Surname $sn -DisplayName $displayName -UserPrincipalName $userPrincipalName -AccountPassword $TempPassword1 -PasswordNeverExpires $true -Path "OU=Service,OU=Accounts,DC=xyz,DC=com"
set-aduser $cn -replace #{comment="xxyyzz"}
set-aduser $cn -replace #{"account"=1}
Add-ADGroupMember -Identity xyz -Member $cn
Add-ADGroupMember -Identity "Service Accounts" -Member $cn
write-host "New DevTable ADUser has been created!!!";
}
catch [Exception]
{
write-host "Error - Requested AD Service Account is already present...Please check & confirm " -foreground "red"
}
}
break;
}
default {"The table could not be determined!!!"}
}
[System.GC]::Collect()
Please have a look.Thanks.
This is written so that $sourceData can be a string like the following. If you really want to pass $sourcedata as an array of char remove the [char[]] cast from the function.
$sourcedata="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-$"
Function GET-Temppassword() {
Param(
[int]$length=10,
[string[]]$sourcedata
)
-join ([char[]] $sourcedata | GET-RANDOM -count $length)
}
get-temppassword $sourceData 20
GVTXxF13ibnBK5AQOu-P