Archive

Posts Tagged ‘Powershell’

Converting SMTP Proxy Addresses to Lowercase

May 14, 2012 4 comments

Update: Be aware, this script has not been tested with SIP, X400 or other address types. I am working on an update to validate these scenarios, but in the meantime, proceed at your own risk with these address types.

I recently encountered a question in an online forum where someone asked for a script to convert all of their user’s email addresses to lower case values.  While this doesn’t affect the message delivery, it can have an impact on aesthetics when the address is displayed in an external recipient’s email client.  An Exchange Email Address Policy can do this to some degree, but I wanted to see how it could be done with PowerShell.

The challenge with a script like this is twofold:

  1. Email addresses (proxy addresses) are a multi-valued attribute, which can be tricky to work with.
  2. PowerShell is generally not case-sensitive, and therefore when we try to rename Mr. Gallalee’s email address in the screenshot below, we can see that it does not work:

WARNING: The command completed successfully but no settings of 'demolab.local/Users/Rob Gallalee' have been modified.

After a little bit of inspiration from a script written by Michael B Smith, I came up with the below:


$MailboxList = Get-Mailbox  -ResultSize unlimited

$MailboxList | % {

$LoweredList = @()
$RenamedList = @()

foreach ($Address in $_.EmailAddresses){
if ($Address.prefixstring -eq "SMTP"){
$RenamedList += $Address.smtpaddress + "TempRename"
$LoweredList += $Address.smtpaddress.ToLower()
}
}
Set-mailbox $_ -emailaddresses $RenamedList -EmailAddressPolicyEnabled $false
Set-mailbox $_ -emailaddresses $LoweredList

#Without this line the "Reply To" Address could be lost on recipients with more than one proxy address:
Set-mailbox $_ -PrimarySmtpAddress $_.PrimarySmtpAddress
}

This script works as follows:

  1. Puts all mailboxes into the $MailboxList variable.  If you don’t want all mailboxes,  edit the Get-Mailbox cmdlet as you see fit.
  2. Filters out X400 and other non-SMTP addresses.
  3. Creates an array called $RenamedList which stores each proxy address with “TempRename” appended to it (e.g. Rgallalee@demolab.localTempRename).
  4. Creates another array ($LoweredList) and use the “ToLower” method on each proxy address.
  5. Sets the proxy address for the user to the value of $RenamedList and then to $LoweredList.
    1. This is how we get around the case case insensitivity – name it to something else and then name it back.
  6. Step 4 and 5 don’t preserve the “Primary” / “Reply-To” address, so we set it back manually with the last line.

Note: This script turns off the email address policy for each user.

As always, feedback is welcome.

Combining PowerShell Cmdlet Results

April 17, 2012 10 comments

In my last post I used used New-Object to create an desirable output when the “Get-Mailbox” cmdlet didn’t meet my needs.  If your eyes glazed over trying to read the script, let me make it a bit simpler by focusing on a straight forward example.

Say you need to create a list of user’s mailbox size with their email address.  This sounds like a simple request, but what you’d soon find is that mailbox sizes are returned with the Get-MailboxStatistics cmdlet and the email address is not.  For that, you need to use another cmdlet, such as Get-Mailbox.

With the New-Object cmdlet, we are able to make a custom output that contains data from essentially wherever we want.

See this example:

$MyObject = New-Object PSObject -Property @{
EmailAddress = $null
MailboxSize = $null
}

In this example, I have created a new object with 2 fields, and saved it as the $MyObject variable.

For now, we’ve set the data to null, as shown below:

$MyObject

The next step is to populate each of those fields.  We can write to them one at a time with lines like this:

$MyObject.EmailAddress = (Get-Mailbox mcrowley).PrimarySmtpAddress
$MyObject.MailboxSize = (Get-MailboxStatistics mcrowley).TotalItemSize

Note: The variable we want to populate is on the left, with what we want to put in it on the right.

To confirm our results, we can simply type the variable name at the prompt:

$MyObject with data

Pretty cool, huh?

Ok, so now about that list.  My example only shows the data for mcrowley, and you probably need more than just 1 item in your report, right?

For this, you need to use the foreach loop.  You can read more about foreach here, but the actual code for our list is as follows:

(I am actually going to skip the $null attribute step here)

$UserList = Get-mailbox -Resultsize unlimited
$MasterList = @()
foreach ($User in $UserList) {
$MyObject = New-Object PSObject -Property @{
EmailAddress = (Get-Mailbox $User).PrimarySmtpAddress
MailboxSize = (Get-MailboxStatistics $User).TotalItemSize
}
$MasterList += $MyObject
}
$MasterList

$MasterList with data

Finally, if you wanted to make this run faster, we really don’t need to run “get-mailbox” twice.  For better results, replace the line:

EmailAddress = (Get-Mailbox $User).PrimarySmtpAddress

With this one:

EmailAddress = $User.PrimarySmtpAddress

Exchange Proxy Address (alias) Report

April 16, 2012 16 comments

###

UPDATE (June 1 2012): This script now runs faster and puts the “Primary” SMTP address first.  For example:

Updated Output

###

Exchange Server stores user’s alternate email addresses as a multi-valued attribute within Active Directory.  For example, if my colleague Jorge has jdiaz@demolab.local as well as diazj@demolab.local, his proxyAddresses attribute would look like this:

ADUC - ProxyAddresses

Notice, the capital SMTP vs. the lowercase smtp.  There can be only one uppercase SMTP, and this represents the primary, or “reply to” address.

While, it’s very easy to view someone’s proxy addresses (often called aliases, but don’t confuse it with the “alias” attribute) within the Exchange Management Console, it can be tough to work with in the Exchange Management Shell (PowerShell) due to the data being stored as a  “Multi-Valued” attribute.  The usual “Get-Mailbox” output not only shows all addresses as a single item, but in the case “mcrowley” below, we can see the shell truncates:

get-mailbox mcrowley | select emailaddresses

While there are ways (example1, example2) to manipulate this output on the screen, I recently needed to create a complete list of all users possessing one or more secondary email address, and document what those addresses were.

On the surface, this sounds simple.  We want a list of users who have more than 1 proxy address.  At first, I thought of something like this:

Get-Mailbox -Filter {emailaddresses -gt 1} | Select EmailAddresses

Get-Mailbox -Filter {emailaddresses -gt 1} | Select EmailAddresses

But we can see this doesn’t actually capture the correct users.  In the above example, LiveUser1 only has a single proxy address, but it was returned anyway.  This is because the result is actually converted to a number, and the “-gt” or “greater than” operation is done on this number; not what we want.

To get the user collection you want, we actually need to break-out the data within this attribute, and evaluate it in a somewhat CPU intensive process.  I have written a script that helps here, by doing the following things:

  • Grabs all mailboxes and counts the number of proxy addresses for each one.  I have filtered out X400, and other non-smtp addresses.
  • If more than one proxy is found, it puts the user and it’s proxy addresses in a “nice” CSV file called c:\TooManyProxies.csv.
  • Displays a similar output to the screen.
  • Displays the total number of users found.

Here is a sample output, shown in excel (with some bolding on the headers):

Sample TooManyProxies.csv

The guts of this script might help with this exact scenario, or really, anywhere you want to break out and evaluate multi-valued attributes.  Feel free to use it and adjust as you see fit!

Some known limitations:

  • I’m no PowerShell master, so this might not be as efficient as it could be.
  • If a user has more than 10 proxy addresses, you’ll need to adjust the script and add more rows.
  • There isn’t a lot of error checking here, but I’ve used it in 2 different environments and it ran as expected.
  • -replace "smtp:"As shown below, this script doesn’t differentiate “SMTP” from “smtp”.  The addresses are listed in order stored; not necessarily relevant to us.  If you want this information shown, remove this portion from the script:

If you ONLY want a csv of everyone’s proxy address, change “-gt 1″ to “-gt 0″

Finally, the script itself:

#ProxyAddressCount-v3.3
# by Mike Crowley http://mikecrowley.us

cls

Write-Host "Getting and evaluating users. Please wait; this could take a while..." -ForegroundColor Cyan

#Getting a list of mailboxes to work with
$UserList = Get-mailbox -Resultsize unlimited

$TooManyProxies = @()

foreach ($User in $UserList) {
#get a list of SMTP and smtp proxy addresses for each User
[array]$SmtpProxyAddresses = $User.emailaddresses | Where {$_.prefixstring -like 'smtp'} | sort IsPrimaryAddress -Descending

#This section creates a lot of errors since many users don't have 3,4,5 etc proxy addresses. Here we turn error output off.
$ErrorActionPreference = 'SilentlyContinue'

#Create a new placeholder object so that we don't store the x400/x500 proxy addresses
$UserAndSmtpObject = New-Object PSObject -Property @{
Name = $user.name
PrimarySmtpAddresses1 =$SmtpProxyAddresses[0] -replace "smtp:"
SmtpAddresses2 =$SmtpProxyAddresses[1] -replace "smtp:"
SmtpAddresses3 =$SmtpProxyAddresses[2] -replace "smtp:"
SmtpAddresses4 =$SmtpProxyAddresses[3] -replace "smtp:"
SmtpAddresses5 =$SmtpProxyAddresses[4] -replace "smtp:"
SmtpAddresses6 =$SmtpProxyAddresses[5] -replace "smtp:"
SmtpAddresses7 =$SmtpProxyAddresses[6] -replace "smtp:"
SmtpAddresses8 =$SmtpProxyAddresses[7] -replace "smtp:"
SmtpAddresses9 =$SmtpProxyAddresses[8] -replace "smtp:"
SmtpAddresses10 =$SmtpProxyAddresses[9] -replace "smtp:"
}

#Turning error reporting back on
$ErrorActionPreference = 'Continue'

#Count the number of proxy addresses for each User
$SmtpProxyAddressCount = ($SmtpProxyAddresses).count

#Add Users with more than 1 proxy address to the $TooManyProxies variable
if ($SmtpProxyAddressCount -gt 1) {
$TooManyProxies += $UserAndSmtpObject
}
}

Write-Host ""
$TooManyProxies | select name, PrimarySmtpAddresses1, SmtpAddresses2, SmtpAddresses3, SmtpAddresses4, SmtpAddresses5, SmtpAddresses6, SmtpAddresses7, SmtpAddresses8, SmtpAddresses9, SmtpAddresses10 | Export-CSV c:\TooManyProxies.csv -notype
$TooManyProxies | select name, PrimarySmtpAddresses1, SmtpAddresses2, SmtpAddresses3, SmtpAddresses4, SmtpAddresses5, SmtpAddresses6, SmtpAddresses7, SmtpAddresses8, SmtpAddresses9, SmtpAddresses10
Write-Host ""

#Display a count
Write-Host "You had" ($TooManyProxies).count "Users containing two or more proxy SMTP addresses." -ForegroundColor Cyan

Write-Host ""
Write-Host ""
Write-Host "Your result file is here 'c:\TooManyProxies.csv'" -ForegroundColor Cyan

PowerShell Tip – Running a Service Pack Report – Faster

February 17, 2011 Leave a comment

Imagine you wanted to run a quick report of all your server’s service pack level in your domain.  After all, SP1 just came out!  You could get this information quickly by using the Active Directory Module for Windows PowerShell.  If you don’t have at least one Windows 2008 R2 (RTM or SP1) Domain Controller, you could also do something similar with the free Quest PowerShell tools, but that’s for another day…

We can find this information using a few different methods.  Here I’ll show two:

Method 1

Get-ADComputer -Properties OperatingSystem, OperatingSystemServicePack -Filter * | Where-Object {$_.OperatingSystem -like '*server*'} |  Format-Table name, oper* -autosize

You can see with Method 1, we’re telling PowerShell to get all the computer accounts from Active Directory.  Then we pass those objects over to the “Where-object” cmdlet and ask it to select only those who have an OperatingSystem attribute containing “server”.  We then format the results in a table.  Give it a try.

Not too shabby; but let’s make it better!

Method2

Get-ADComputer -Properties OperatingSystem, OperatingSystemServicePack -Filter {OperatingSystem -like '*server*'} | Format-Table name, oper* -autosize

In Method 2, we’re making smarter use of the –Filter switch.  So instead of getting ALL the computer accounts, we do our filtering up-front.  This can lead to significant amount of time saved!

How much time, you ask?  Well, we can find out with the “Measure-Command” cmdlet.  Just put any command string in {} and it will tell you how long it took to run!

Here are the results from a small environment with fast servers. 677 milliseconds isn’t bad, but when you compare it to 73, you can begin to appreciate the potential.

clip_image001

One last thought:  You may wish to add this extra code to make your output prettier.  It will organize your results first by operating system and then by name:

Get-ADComputer -Properties OperatingSystem, OperatingSystemServicePack -Filter {OperatingSystem -like '*server*'} | Sort-Object operatingsystem, name | Format-Table name, oper* -autosize

Script for Missing UPNs

December 14, 2010 4 comments

For various reasons I’ve found myself needing to fix customer sites where the User Principal Name (UPN) was not present for AD user accounts.

image

Most frequently this is because the environment was once NT4, which did not require this attribute.  Whatever the reason, I’ve fixed it using PowerShell.

If you don’t have 2008 R2 domain controllers you can use the free Quest PowerShell add-ins downloaded here.

If you DO have 2008 R2 domain controllers you can use the native Active Directory Module for Windows PowerShell.

Below is a script you can use for either scenario.  This will take all users with missing UPNs from the “My Users” OU in the “contoso.local” domain and set their UPN to username@contoso.local

Quest:

Get-QADUser –SearchRoot “contoso.local/My Users” -UserPrincipalName $null -SizeLimit 0 | % {$CompleteUPN = $_.samaccountname +"@contoso.local"; Set-QADUser -Id $_.DN -UserPrincipalName $CompleteUPN}

2008 R2 Native:

Get-ADUser  -Filter {-not (UserPrincipalName -like '*')} -SearchBase 'OU=My Users,DC=contoso,DC=local' | % {$CompleteUPN = $_.SamAccountName + "@contoso.local" ; Set-ADUser -Identity $_.DistinguishedName -UserPrincipalName $CompleteUPN}

Converting a Mailbox to a MailUser (and not losing attributes)

December 9, 2010 4 comments

It’s not often that you’ll need to convert a mailbox to a mail-user, but when you do, you’ll soon realize the steps go like this:

1. Mail-Disable the user (delete the mailbox)
2. Mail-Enable the user

So what’s the problem?  The problem is twofold:

  • First, you’ll want to automate this, and there is no “convert” button or command.  You’ll need to use PowerShell if converting multiple users.
  • Second, and perhaps more importantly, all the Exchange attributes are nullified
    when you delete the mailbox.  This includes CustomAttribute1-15

As we can see, you are not able to pass mailboxes to the Enable-MailUser as you are able to do in reverse:

image
I’ve written a script to solve these problems.  Before you run with it, you do need to make one decision:

What do you want the mail-user’s external email address to be?

The below script takes the user’s mailbox alias and then appends @domain.com.

You may wish to modify this with whatever their new external address has become.

You’ll also notice I’m using DC123 as my domain controller for all configurations.  I have found in my testing that if you do not pick the same DC for all operations, the script could out run AD replication.

$MailboxList = Get-Mailbox
foreach ($Mailbox in $MailboxList)
{

Disable-Mailbox -ID
$mailbox.Identity -Confirm:$False -DomainController DC123;

Enable-MailUser -Id
$mailbox.Identity -ExternalEmailAddress
($mailbox.alias + "@domain.com")
-DomainController DC123;

Set-MailUser -Id

$mailbox.Identity -DomainController DC123 -CustomAttribute1 $Mailbox.CustomAttribute1 –CustomAttribute2 $Mailbox.CustomAttribute2 –CustomAttribute3 $Mailbox.CustomAttribute3 –CustomAttribute4 $Mailbox.CustomAttribute4 –CustomAttribute5 $Mailbox.CustomAttribute5 –CustomAttribute6 $Mailbox.CustomAttribute6 –CustomAttribute7 $Mailbox.CustomAttribute7 –CustomAttribute8 $Mailbox.CustomAttribute8 –CustomAttribute8 $Mailbox.CustomAttribute8 –CustomAttribute9 $Mailbox.CustomAttribute9 –CustomAttribute10 $Mailbox.CustomAttribute10 –CustomAttribute11 $Mailbox.CustomAttribute11 –CustomAttribute12 $Mailbox.CustomAttribute12 –CustomAttribute13 $Mailbox.CustomAttribute13 –CustomAttribute14 $Mailbox.CustomAttribute14 –CustomAttribute15 $Mailbox.CustomAttribute15

}
Follow

Get every new post delivered to your Inbox.

Join 35 other followers