Monthly Archives: April 2014

Sending custom “password is about to expire” notifications with PowerShell

Sending out reminders to your users about changing their password before it expires could really take some load of the Helpdesk, and there are a few scripts available that does just that. What I found was that most of these scripts were assuming that everyone in the organization should get the same e-mail, which is not always true.

Therefore I wrote a new one where you could specify how the e-mail should look depending on where in your organization the user works. In our case, we needed to have different languages for different countries, the instructions were different aswell (some users needed to use a password change portal to change their passwords, others are using the classic “CTRL + ALT + DELETE”-method). We also have different contact information for the helpdesk in those countries and departments.

I will do a walk-through of this script to help you customize it to fit your organisation.

The first thing you need to do, is to decide when the users should receive a notification. This is done with these variables:

# Set when users should get a warning...

# First time
$FirstPasswordWarningDays = 14

# Second time
$SecondPasswordWarningDays = 7

# Last time
$LastPasswordWarningDays = 3

Users will then receive a warning 14 days, 7 days and finally 3 days before the password expires. Depending on how the number of days are rounded in the e-mail, it may differ a day from what you specify here.

You then need to set what smtp-server to use:

# Set SMTP-server
$SMTPServer = "MySMTP.Contoso.Com"

There is no need to change the next part of the code, it basically is just calculating when passwords will expire based on your domain policy and what you set in the variables above. It looks like this:

# Get the password expires policy
$PasswordExpiresLength = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge

# Calculating when passwords would have been set if they expire today
$CurrentPWChangeDateLimit = (Get-Date).AddDays(-$PasswordExpiresLength.Days)

# Calculating all dates
$FirstPasswordDateLimit = $CurrentPWChangeDateLimit.AddDays($FirstPasswordWarningDays)
$SecondPasswordDateLimit = $CurrentPWChangeDateLimit.AddDays($SecondPasswordWarningDays)
$LastPasswordDateLimit = $CurrentPWChangeDateLimit.AddDays($LastPasswordWarningDays)

We are now ready to load the users, you might want to adjust the filter a bit depending on how your Active Directory design is. Just edit the first part of the filter (Mail -like ‘*@*’) to do this.

# Load the users
$MailUsers = Get-ADUser -Filter "(Mail -like '*@*') -AND `
(PasswordLastSet -le '$FirstPasswordDateLimit' -AND PasswordLastSet -gt '$($FirstPasswordDateLimit.AddDays(-1))' -OR `
PasswordLastSet -le '$SecondPasswordDateLimit' -AND PasswordLastSet -gt '$($SecondPasswordDateLimit.AddDays(-1))' -OR `
PasswordLastSet -le '$LastPasswordDateLimit' -AND PasswordLastSet -gt '$($LastPasswordDateLimit.AddDays(-1))') -AND `
(PasswordNeverExpires -eq '$false' -AND Enabled -eq '$true')" -Properties PasswordLastSet, DisplayName, PasswordNeverExpires, mail

We now got all the users, we just need to loop through them and send out the e-mails. This is where we need to specify which users should get which e-mail.

The comments should give you the information you need to customize it for your environment. Make sure you check out lines 13 and 19 below and change “MyOU1” and “MyOU2” to match your Organizational Units in Active Directory.

# Loop through them
foreach ($MailUser in $MailUsers) {

# Count how many days are left before the password expires and round that number
$PasswordExpiresInDays = [System.Math]::Round((New-TimeSpan -Start $CurrentPWChangeDateLimit -End ($MailUser.PasswordLastSet)).TotalDays)

# Write some status...
Write-Output "$($MailUser.DisplayName) needs to change password in $PasswordExpiresInDays days."

# Build the body depending on where in the organisation the user is

# Change MyOU1 to match your the OU you want your users are in.
if ($MailUser.DistinguishedName -like "*MyOU1*") {
$Subject = "Your password is expiring in $PasswordExpiresInDays days"
$Body = "Hi $($MailUser.DisplayName),

Your password is expiring in $PasswordExpiresInDays days. Please change it now!

Don't forget to change it in your mobile devices if you are using mailsync.

Helpdesk 1"
$EmailFrom = "Helpdesk 1 <[email protected]>"
}
# Change MyOU2 to match your environment
elseif ($MailUser.DistinguishedName -like "*MyOU2*") {
$Subject = "Your password is expiring in $PasswordExpiresInDays days"
$Body = "Hi $($MailUser.DisplayName),

Your password is expiring in $PasswordExpiresInDays days. Please change it now!

Don't forget to change it in your mobile devices if you are using mailsync.

Helpdesk 2"
$EmailFrom = "Helpdesk 2 <[email protected]>"
}
# This is the default e-mail
else {
$Subject = "Your password is expiring in $PasswordExpiresInDays days"
$Body = "Hi $($MailUser.DisplayName),

Your password is expiring in $PasswordExpiresInDays days. Please change it now!

Don't forget to change it in your mobile devices if you are using mailsync.

Helpdesk 3"
$EmailFrom = "Helpdesk 3 <[email protected]>"
}

# Time to send the e-mail

# The line below might need changing depending on what SMTP you are using (authentication or not)
Send-MailMessage -Body $Body -From $EmailFrom -SmtpServer $SMTPServer -Subject $Subject -Encoding UTF8 -BodyAsHtml -To $MailUser.mail

# E-mail is sent!
}

You also need to change the body/subject/mailfrom variables to match what you want to send out. Just add more “elseif”-clauses if you want to send out more versions, or remove them if you don’t need them.

And make sure you configure the “Send-MailMessage”-cmdlet correctly to use your smtp-server if you use authentication or a different port.

All you need to do after that is to schedule the script to run at the same time every day and you are done! (And some testing of course… ūüôā )

Leave a comment if you have any questions!

The complete and uncut code is available here.

Let’s build a Infoblox PowerShell Module!

If you haven’t heard of it, Infoblox is making appliances and solutions for enterprise networks. One of them is the Infoblox Trinzic DDI¬†which manages DNS, DHCP and IPAM.

Infoblox does not seem to have any plans for delivering a PowerShell module for managing their product, which is a bit weird since it would probably make it a bit easier for network admins trying to move windows engineers away from Active Directory Integrated DNS, and instead let the Infoblox appliance host all or some of their zones (which seems to be a common enough debate among enterprises).
But in their defence they have released a REST-based API for this appliance which enables administrators to basically build whatever tools they want to manage anything from DNS records to IPAM.

I’ve therefore started to build a module for managing DNS-records hosted by the Infoblox, but since my experience with this product is fairly limited, I thought I would post what I’ve done so far to get opinions from people with more experience with this product.

I’ve only done a few¬†cmdlets (advanced functions) for managing¬†a few¬†common DNS record tasks. So far these are:

  • Add-IBResourceRecordA
  • Add-IBResourceRecordCName
  • Add-IBResourceRecordHost
  • Get-IBResourceRecord
  • Remove-IBResourceRecord
  • Set-IBResourceRecord

Some usage examples:

# Adding a A-record
Add-IBResourceRecordA -IPv4Address 1.2.3.4 -HostName myhost.contoso.com -GridServer $MyInfobloxGrid -Credential $MyCredential

# Adding a hundred A-records
1..100 | % { Add-IBResourceRecordA -IPv4Address 1.2.3.$_ -HostName myhost$_.contoso.com -GridServer $MyInfobloxGrid -Credential $MyCredential }

# Searching for those records
Get-IBResourceRecord -RecordType A -RecordValue myhost* -GridServer $MyInfobloxGrid -Credential $MyCredential

# Search for a record by IP-address
Get-IBResourceRecord -RecordType A -SearchField ipv4addr -RecordValue 1.2.3.4 -GridServer $MyInfobloxGrid -Credential $MyCredential

# Removing all of them
Get-IBResourceRecord -RecordType A -RecordValue myhost* -GridServer $MyInfobloxGrid -Credential $MyCredential -Passthrough | Remove-IBResourceRecord

# Add a HOST record
Add-IBResourceRecordHost -IPv4Address 1.2.3.4 -HostName myhost.contoso.com -GridServer $MyInfobloxGrid -Credential $MyCredential

# Change the IP-address of that record (A-record needs some tweaking before they work, I'm working on it...)
Get-IBResourceRecord -RecordType Host -RecordValue myhost.contoso.com -GridServer $MyInfobloxGrid -Credential $MyCredential -Passthrough | Set-IBResourceRecord -IPv4Address 4.3.2.1

# Add a CName
Add-IBResourceRecordCName -HostName cname.contoso.com  -Canonical myhost2.contoso.com -GridServer $MyInfobloxGrid -Credential $MyCredential

Screenshot:
Infoblox module in action...

This is very early in the development of this module, so it probably have a few bugs, and there are a lot of cmdlets that needs to be written!

Anyone out there that wants help or have any thoughts?

Please post a comment here or join this thread in the Infoblox community forum.

The code for this early version of the module is available at the Github repo!

Buying groceries with PowerShell

Yes, really, buying groceries can also be done with PowerShell!

How? Well, you need to find someone who sells groceries through a website, and can deliver them to your house.

The rest is just webrequests!

This is not only (but maybee mostly… ūüėČ ) made as a part of my weird quest for doing strange things with PowerShell, but also a small¬†part of my home automation project. I’ll give you some usage examples:

  • Let’s say the weather-cmdlet posted earlier gives you reports about rain, wind and cold weather for the coming week, how about adding some popcorn to your basket and other things you want for a nice movie-night at home?
  • Your favorite TV show is ending next week, add those popcorns again!
  • If the weather looks nice… order some things needed for a picnic?
  • Connect it to your voice control made with powershell¬†and ask it to, for example, “add milk” when you take the last one from the fridge.
  • An anniversary is coming up (I have written a cmdlet for checking this, post is coming!), let’s order flowers! (Romance is all about¬†spontaeous things, right? ūüėČ )
  • Find an intelligent fridge with an ethernet/WiFi connection and… well… maybee not ūüėČ

Alright… Nothing lifechanging… But it still shows how versatile PowerShell can be, which is sort of my main point with all this!

This is a small example of how it looks in action:
mathem

The code can be downloaded through this link. (updated at 2016-10-06)

Since it will only be useful for Swedish users who live in cities where this service is available, the rest of you can just look at it as sample code if you want to do something similar.