- Automate out-of-office messages in Outlook with Visual Basic for Applications (VBA) - Fri, Jan 5 2018
- Add a signature to Office 365 emails with PowerShell - Mon, Nov 11 2013
- Restore Administrative Unlock to Windows 7 - Fri, Oct 4 2013
Like a lot of schools in the UK and around the world, we use Microsoft Office 365 for our email service. All of our users use the web app exclusively to check their mail.
One thing that is lacking is the ability to centralize the management of user signatures and to ensure that those signatures conform to corporate standards without third-party tools. In this post, I’ll take you through some PowerShell scripts that can help you get a handle on this issue.
Added signature in Office 365
I currently have this functionality split into two scripts: the first script exports details from Active Directory and generates some HTML files for the signatures, and the second script pushes those signatures to the users’ Office 365 accounts.
These scripts are provided for you to use at your own risk. Note that there is currently no error checking, and you must test the scripts before deploying them in a production environment. I tested the create script on a Windows Server 2008 R2 Domain Controller and the push script on a Windows 7 Enterprise 64-bit client, but there is no reason why, in your environment, you couldn’t run both from the server.
It’s also possible that you could combine the two scripts into one and run the combined script as a scheduled job. The scripts are provided merely as a starting base for you to work from.
I welcome suggestions for additions and modifications to the scripts.
Create an Office 365 signature
The script first imports the required PowerShell module. The save location must exist and should be completely empty when the script first runs; on subsequent runs, the script will overwrite the output .htm files anyway.
#import the active directory module which is needed for Get-ADUser import-module activedirectory #set folder location for files, the folder must already exist $save_location = 'c:\file_location\' #$users = Get-ADUser -filter * -searchbase "OU=Testing,OU=Staff,OU=Test Users,DC=bigcheese,DC=com" -Properties * -Credential bigcheese\admin -Server bigcheese.com $users = Get-ADUser -filter * -searchbase "OU=Testing,OU=Staff,OU=Test Users,DC=bigcheese,DC=com" -Properties * foreach ($user in $users) { $full_name = “$($user.GivenName) $($User.Surname)” $account_name = "$($User.sAMAccountName)" $job_title = "$($User.title)" $location = "$($User.office)" $dept = "$($User.department)" $comp = "$($User.company)" $email = "$($User.emailaddress)" $phone = "$($User.telephoneNumber)" $logo = "$($User.wWWHomePage)" #We need to construct and write the html signature file $output_file = $save_location + $account_name + ".htm" Write-Host "Now attempting to create signature html file for " $full_name "<span style=`"font-family: calibri,sans-serif;`"><strong>" + $full_name + "</strong><br />", $job_title + " - " + $location + "<br />", $dept + "<br />", $comp + "<br />", $phone + "<br />", "</span><br />", "<img alt=`"corporate logo`" border=`"0`" height=`"90`" src=`"" + $logo + "`" width=`"385`" />" | Out-File $output_file }
The script uses the Get-ADUser cmdlet to retrieve information from AD. The -searchbase parameter is used to target it to a specific OU. Now that we have all the properties from all users in that OU as an array in $users, we can process the user information.
Properties of a user object in Active Directory
The For loop goes through this array, pulls out the specified AD fields, and stores them as parameters. A full list of the fields can be found here.
The script uses the wWWHomePage field to store the location to a publicly accessible image that will be included in our signature file.
Next, the script constructs a CSS/HTML file containing the selected fields and writes the file to the $save_location folder in the format username.htm. You can open this file in a web browser to make sure it looks as you expected.
Push the signature to Office 365
Now that we’ve created an HTML signature file for each user, we have to connect to Office 365 and push this HTML to their signature.
#set folder location for files, the folder must allready exist $save_location = 'file_location' $email_domain = '@bigcheese.com' #connect to O365 tenant $Cred = Get-Credential $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $Cred -Authentication Basic –AllowRedirection Import-PSSession $Session #Get a list of all the filenames in the target folder $sig_files = Get-ChildItem -Path $save_location #Now push the html to the users signature foreach ($item in $sig_files) { $user_name = $($item.Basename) + $email_domain $filename = $save_location + $($item.Basename) + ".htm" Write-Host "Now attempting to set signature for " $user_name set-mailboxmessageconfiguration -identity $user_name -signaturehtml (get-content $filename) -autoaddsignature $true } #disconnect O365 connection get-PSSession | remove-PSSession
The $save_location variable must be set to the folder containing the HTML signature files.
You’ll be prompted for some login credentials for Office 365; these credentials must be for a user who can access and write to the users’ signatures. I use my global admin account for this.
Get-ChildItem is used to create a list of all the files in the $save_location folder. The cmdlet creates an array of the file names so we can run through the individual file names in a For loop.
$($item.Basename) retrieves just the file name with no extension. This result is quite handy as, in this instance, it’s also providing us the user name for the user we are going to edit once it is combined with the $email_domain.
set-mailboxmessageconfiguration -identity $user_name -signaturehtml (get-content $filename) -autoaddsignature $true
The set-mailboxmessageconfiguration command is the one that does the magic and puts the HTML file into the user’s signature. Unfortunately, the command doesn’t return anything so there is no way to be 100% sure it worked.
At the end, the connection to the Office 365 service is disconnected. Users will have to log out and log back in before the new signature takes effect.
I have a few questions.
What is the position of the signature when people reply to emails? Is it appended at the bottom or is it inserted at the top?
Can there be different signatures for new emails and reply-emails? Like it is possible right now, when you set different signatures in outlook-client.
Does this work in Outlook and lets say mobile devices like iOS alltogether?
Is the signature visible to the user, while he/she is composing the message or is the signature created on the server, after the user has already sent the mail?
The signature is positioned in exactly the same place as if you edited the signature yourself in the web app, i.e under your reply.
When you reply to an email the signature is still put in the same place under your text and above the previous email.
There is only one signature as all the script does is push the contents of an html file to the users signature in Office 365.
I’ve no idea what happens when you connect and outlook client to Office 365 or ios I’m sorry we support users using the outlook web app only.
Yes the signature is visible to the user when they are composing an email as it’s is their signature.
Outlook has to have signatures added through the Outlook interface, alas; and they don’t roam. would love a powershell to save my signatures in skydrive/pro and add them to a new PC 😉
Thanks for the great article. I have two questions.
1. I tried to embed a base64 encoded image in the email signature. When I tried to send an email through office 365, I got an error where the image should have been that says “Error! Filename not specified”. Any ideas on how to embed an image in the HTML signature?
2. I am connected to outlook through my windows account “mail” settings. The signature has not propagated to my outlook client, and I can’t “logout” because I am using the settings on the windows account. How can I get the client to use the updated signature?
Cheers,
Daniel
@Daniel
Nice thought on embedding an image that way but I have no idea if that’s supposed to be supported or not as the only way we found was to link to a hosted image.
This method is for creating AD populated signatures in Office 365 on the web only as that’s the functionality we required and is how it’s tested so I cannot help with your particular situation.
Sorry.
Ben
What to say but thank you sooo much for this code. it is exactly what I needed !
I love this code! It’s working perfectly for me for OWA but I’m not getting it to show up in my Outlook 2013 clients. We have a hybrid O365 deployment. Do the signatures perhaps need to be installed in the local AD rather than on O365 in my case?
I’d like to PREVENT users having an OWA signature as I append one via transport rules. I have disabled the ability to create one in OWA but this does not get rid of existing ones.
This is a simply superb solution! Thanks so much for this, it has saved us using essential funding for our school, and I’ve now generated all the staff signatures and even enforced them into outlook via GPO using the following script, which I hope others might find useful:
md %appdata%\microsoft\signatures\
copy \\server\sigs\%USERNAME%.htm %appdata%\microsoft\signatures
REG ADD HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Common\MailSettings\ /v NewSignature /t REG_EXPAND_SZ /d %USERNAME% /f
REG ADD HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\14.0\Common\MailSettings\ /v NewSignature /t REG_EXPAND_SZ /d %USERNAME% /f
REG ADD HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Common\MailSettings\ /v ReplySignature /t REG_EXPAND_SZ /d %USERNAME% /f
REG ADD HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\14.0\Common\MailSettings\ /v ReplySignature /t REG_EXPAND_SZ /d %USERNAME% /f
I just have a couple of questions regarding problems with usernames not matching email addresses. A lot of staff still use a unique ‘r’ number to login, but their email addresses differ from this. I have since ensured any new user names match up with the email addresses, but when running the 2nd script, I’m getting errors due to ‘r’@domain.com not matching up to their actual email address. Is there anything you might be able to suggest that could help me out, and match up the output to the correct email addresses?
Thanks again!
Ah, scratch that last request, I figured out a way around it!
Huge thanks once again!
Hi Paul,
Ben here glad you’ve found is useful even after I first wrote it 4 years ago.
What was your solution to the other issue?
Regards,
Ben
I Love you Ben Norcutt
Ditto, Christian – the above script was crucial to us resolving signature enforcement!
This is now happily running alongside local outlook signature enforcement for all staff here, and has been for some time now.
In response to your query Ben, I resolved the name mismatch issue by generating 2 lots of the same signatures in separate folders, each were named by username and email address. The latter of which I could then use to upload to o365 and copy to the local users signature folder – a tad inefficient, but the easiest way I could see around it at the time.
I now use 2 scripts – one to generate the two sets of html signatures based on AD details, and Ben’s one to upload the generated signatures to office 365 user accounts.
I also created a user logon script to copy signatures into the user’s signature folder, and enforce the signature for that user when they use outlook.
It’s not perfect, but that’s mainly down to the mess we have with usernames and email address differences.
Modified versions are as follows:
1. Script to pull details from AD and generate signature:
#import the active directory module which is needed for Get-ADUser
import-module activedirectory
#set folder location for files, the folder must already exist
$save_location = ‘\\server\sigs\’
$save_location2 = ‘\\server\sigs\o365\’
#$users = Get-ADUser -filter * -searchbase “OU=Office 365,DC=domain,DC=org,DC=uk” -Properties * | ? {$_.distinguishedname -notmatch ‘OU=Students*’} | -Credential domain\administrator -Server company.org.uk
$users = Get-ADUser -filter * -searchbase “OU=Office 365,DC=domain,DC=org,DC=uk” -Properties * | ? {$_.distinguishedname -notmatch ‘OU=Students*’}
foreach ($user in $users) {
$full_name = “$($user.GivenName) $($User.Surname)”
$account_name = “$($User.sAMAccountName)”
$job_title = “$($User.title)”
$comp = “A Building , A Road, Timbuktu, AA1 0BB”
$email = “$($User.emailaddress)”
$phone = If ($User.telephoneNumber -gt 0) {“Ext.”+”$($User.telephoneNumber)”} else {$phone = “”}
$logo = “http://www.website.org.uk”
#Construct and write the html signature file
$output_file = $save_location + $account_name + “.htm”
$output_file1 = $save_location + $User.userPrincipalName + “.htm”
$output_file2 = $save_location2 + $User.mail + “.htm”
Write-Host “Now attempting to create signature html file for ” $full_name
“<p span style=`”font-family:calibri;`”><table><tr><td><a href=`”http://www.website.org.uk`”><img src=`”iconsingle.jpg`”></img></a></td><td><font face=`”calibri`” size=`”3`”><b> $full_name </b><br></font><font face=`”calibri`” size=`”2`”> $job_title <br>A Building , A Road, Timbuktu, AA1 0BB<br>Tel: 01234 567890<br>$phone<br><a href=`”http://www.website.org.uk`”>www.website.org.uk</a><br></font></td></table></span></p> ” | Out-File $output_file
“<p span style=`”font-family:calibri;`”><table><tr><td><a href=`”http://www.website.org.uk`”><img src=`”iconsingle.jpg`”></img></a></td><td><font face=`”calibri`” size=`”3`”><b> $full_name </b><br></font><font face=`”calibri`” size=`”2`”> $job_title <br>A Building , A Road, Timbuktu, AA1 0BB<br>Tel: 01234 567890<br>$phone<br><a href=`”http://www.website.org.uk`”>www.website.org.uk</a><br></font></td></table></span></p> ” | Out-File $output_file2
}
pause
2. Script to upload to office 365 accounts:
#set folder location for files, the folder must already exist
$save_location = ‘\\server\sigs\o365\’
$email_domain = ‘@website.org.uk’
#connect to O365 tenant
$Cred = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $Cred -Authentication Basic –AllowRedirection
Import-PSSession $Session
#Get a list of all the filenames in the target folder
$sig_files = Get-ChildItem -Path $save_location
#Now push the html to the users signature
foreach ($item in $sig_files) {
$user_name = $($item.Basename)
$filename = $save_location + $($item.Basename) + “.htm”
Write-Host “Now attempting to set signature for ” $user_name
set-mailboxmessageconfiguration -identity $user_name -signaturehtml (get-content $filename) -autoaddsignature $true
}
#disconnect O365 connection
get-PSSession | remove-PSSession
pause
3. And finally, the logon script to copy to local signatures folder on client computers for outlook users. (Remove the 2nd line to keep users previous signatures):
md %appdata%\microsoft\signatures\
del %appdata%\microsoft\signatures\*.* /y
copy \\albert\sigs\%USERNAME%.htm %appdata%\microsoft\signatures /y
REG ADD HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Outlook\Options\Mail\ /v EditorPreference /t REG_DWORD /d 131072 /f
REG ADD HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Common\MailSettings\ /v NewSignature /t REG_EXPAND_SZ /d %USERNAME% /f
REG ADD HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\14.0\Common\MailSettings\ /v NewSignature /t REG_EXPAND_SZ /d %USERNAME% /f
REG ADD HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Common\MailSettings\ /v ReplySignature /t REG_EXPAND_SZ /d %USERNAME% /f
REG ADD HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\14.0\Common\MailSettings\ /v ReplySignature /t REG_EXPAND_SZ /d %USERNAME% /f
Hope this is of some use to people – big thanks and most credit to Ben!
How can I create conditions? For example if $job_title or $phone is not empty.
any one had trouble creating the current signature file?
because mine didn’t appeared.
What about using modern authentication as Microsoft have disabled basic authentication for all tenants?