Score:2

Microsoft Powershell Signature Script - Stopped working with latest office 365 build

lb flag

This is my first post on here, so I hope I get all the information across to you!

Firstly, I know that there are paid solutions that can do this, but this solution has been working for the company that I work for a little while now. Therefore, I would like to get it working on all versions of office that we use on site - 2013 through to Office 365. Plus, it makes it a bit more interesting if something is maintained and created on site be it all slightly more difficult.

The problem we see is that signatures have stopped pushing out to users with the latest office 365 build. On top of that, Microsoft won't let me update to this later version so therefore I am unable to diagnose the issue without great impact to certain affected users. I assume this as the signature screen looks completely different to mine but also have yet to confirm - will make this a priority this morning.

Extra Info 11/10/2022: The files and modified template files are reaching the Signature location within Windows Signature location, but the newest version of Office 365 does not pick this up. If I manually create a Signature within office the Files are all there, be it with a couple of extra files (rich text and text formats) as well as the ones created from the script but only the ones manually created appear in outlook. I am confident therefore it's not entirely the script but rather a change within outlook that has stopped the signatures from being pickup up

Here is the PowerShell code in full:

# Gets the path to the user appdata folder
$AppData = (Get-Item env:appdata).value
# This is the default signature folder for Outlook
$localSignatureFolder = $AppData+'\Microsoft\Signatures'
# This is a shared folder on your network where the signature template should be
$templateFilePath = **THE FILE PATH TO THE TEMPLATE SIGNAUTRE**

# Get the current logged in username
$un = $env:username

# The following 5 lines will query AD and get an ADUser object with all information
$filter = "(&(objectCategory=User)(samAccountName=$un))"
$searcher = New-Object System.DirectoryServices.DirectorySearcher
$searcher.Filter = $filter
$ADUserPath = $searcher.FindOne()
$ADUser = $ADUserPath.GetDirectoryEntry()

# Now extract all the necessary information for the signature
$name = $ADUser.DisplayName
$email = $ADUser.mail
$job = $ADUser.title
$landline = $ADUser.telephonenumber
$mobile = $ADUSer.mobile
$office = $ADUser.physicalDeliveryOfficeName
$so = $ADUser.description
$adchangedate = $ADUser.whenChanged

# Placeholder on html file association
$namePlaceHolder = "\[DISPLAY_NAME\]"
$emailPlaceHolder = "\[EMAIL\]"
$jobPlaceHolder = "\[JOB_TITLE\]"
$folderPlaceHolder = "\[FOLDER_PATH\]"
$phonePlaceHolder = "\[TELEPHONE\]"
$SOPlaceHolder = "\[SIGN_OFF\]"

# Save it as <username>.htm
$namefolder = $un + " (" + $email + ")_files";
$namefolder2 = $un + "_Reply (" + $email + ")_files";
$filename = $localSignatureFolder + "\" + $un + " (" + $email + ").htm";
$filename2 = $localSignatureFolder + "\" + $un + "_reply" + " (" + $email + ").htm";
$foldername = $localSignatureFolder + "\" + $namefolder;
$foldername2 = $localSignatureFolder + "\" + $namefolder2;
$templatefolderpath = $templateFilePath + "\Harboro_template_files\*";
$templatefolderpath2 = $templateFilePath + "\Harboro_Reply_template_files\*";

#NO EMAIL ON AD, NO SIGNATURE
if ($email -ne "") 
{

#change contents of template html file to work with the script below, only if template has been changed from the original
#Asign varibale to pint at particlular file
$rawtemp = get-content $templateFilePath"\Harboro_template.htm"
$rawtemp2 = get-content $templateFilePath"\Harboro_Reply_template.htm"
$check1 = ($rawtemp | Select-String -Pattern "Harboro_template_files").count
$check2 = ($rawtemp2 | Select-String -Pattern "Harboro_Reply_template_files").count

if ($check1 -ne 0 -or $check2 -ne 0)
{
#MAIN TEMPLATE CONTENTS
$newContent = $rawtemp -replace "Harboro_template_files","[FOLDER_PATH]"
$newContent | Set-Content -Path $templateFilePath"\Harboro_template.htm" -force
#REPLY TEMPLATE CONTENTS
$newContent2 = $rawtemp2 -replace "Harboro_Reply_template_files","[FOLDER_PATH]"
$newContent2 | Set-Content -Path $templateFilePath"\Harboro_Reply_template.htm" -force
#RESET THE RAWTEMP VARAIBLE WITH NEW FILE CONTENTS
$rawtemp = get-content $templateFilePath"\Harboro_template.htm"
$rawtemp2 = get-content $templateFilePath"\Harboro_Reply_template.htm"
}

#find place holders and convert them to users data from AD variables
if ($so -eq "")
{
$sig = $rawtemp -replace $SOPlaceHolder,""
$rawtemp = $sig
$sig2 = $rawtemp2 -replace $SOPlaceHolder,""
$rawtemp2 = $sig2
}
else {
$sig = $rawtemp -replace $SOPlaceHolder,$so
$rawtemp = $sig
$sig2 = $rawtemp2 -replace $SOPlaceHolder,$so
$rawtemp2 = $sig2
}

$sig = $rawtemp -replace $namePlaceHolder,$name
$rawtemp = $sig
$sig2 = $rawtemp2 -replace $namePlaceHolder,$name
$rawtemp2 = $sig2

$sig = $rawtemp -replace $emailPlaceHolder,$email
$rawtemp = $sig
$sig2 = $rawtemp2 -replace $emailPlaceHolder,$email
$rawtemp2 = $sig2

if ($mobile -ne "")
{
$phone = $landline + "&nbsp;&nbsp;&nbsp;Mobile:&nbsp;&nbsp;" + $Mobile
}
else {
$phone = $landline
}

$sig = $rawtemp -replace $phonePlaceHolder,$phone
$rawtemp = $sig
$sig2 = $rawtemp2 -replace $phonePlaceHolder,$phone
$rawtemp2 = $sig2

$sig = $rawtemp -replace $jobPlaceHolder,$job
$rawtemp = $sig
$sig2 = $rawtemp2 -replace $jobPlaceHolder,$job
$rawtemp2 = $sig2

$sig = $rawtemp -replace $folderPlaceHolder,$namefolder
$sig2 = $rawtemp2 -replace $folderPlaceHolder,$namefolder2

# Determines daylight saving
$adchangedate = write-output $adchangedate
$adchangedate = [DateTime]$adchangedate
if ($adchangedate.IsDaylightSavingTime() -eq $true)
    {
        $adchangedate = $adchangedate.AddHours(1)
    }

#IMAGES FOLDER
#If Signature supporting folder exists checks 
if (Test-Path -Path $foldername) {
        $SourceDocs = Get-ChildItem –Path $templatefolderpath | foreach  {Get-FileHash –Path $_.FullName}
        $DestDocs = Get-ChildItem –Path $foldername | foreach  {Get-FileHash –Path $_.FullName}
        $count = (Compare-Object -ReferenceObject $SourceDocs -DifferenceObject $DestDocs  -Property hash -PassThru).count
        $SourceDocs2 = Get-ChildItem –Path $templatefolderpath2 | foreach  {Get-FileHash –Path $_.FullName}
        $DestDocs2 = Get-ChildItem –Path $foldername2 | foreach  {Get-FileHash –Path $_.FullName}
        $count2 = (Compare-Object -ReferenceObject $SourceDocs2 -DifferenceObject $DestDocs2  -Property hash -PassThru).count 
        # If changes in folder, then update else do nothing
        if ($count –ne 0){
            Remove-Item -Path $foldername -recurse -force
            New-Item -Path $foldername -ItemType Directory
            Copy-Item -Path $templatefolderpath -Destination $foldername -PassThru -force;
        }
        if ($count2 –ne 0){
            Remove-Item -Path $foldername2 -recurse -force
            New-Item -Path $foldername2 -ItemType Directory
            Copy-Item -Path $templatefolderpath2 -Destination $foldername2 -PassThru -force;
        }
} else {
   # if folder does not exist then create directory
    New-Item -Path $foldername -ItemType Directory
    Copy-Item -Path $templatefolderpath -Destination $foldername -PassThru -force;
    New-Item -Path $foldername2 -ItemType Directory
    Copy-Item -Path $templatefolderpath2 -Destination $foldername2 -PassThru -force;
}

#MAIN SIGNATURE
# Gets the last update time of the template.
if(test-path $templateFilePath){
    $templateLastModifiedDate = [datetime](Get-ItemProperty -Path $templateFilePath -Name LastWriteTime).lastwritetime
}

# Checks if there is a signature and its last update time
if(test-path $filename){
    $sigLastModifiedDate = [datetime](Get-ItemProperty -Path $filename -Name LastWriteTime).lastwritetime
    if((get-date $templateLastModifiedDate) -gt (get-date $sigLastModifiedDate)){
        $sig > $filename
    }
    # If an AD change has been made and the created signature is older, then update signature. 
    elseif(($adchangedate) -gt (get-date $sigLastModifiedDate)){
        $sig > $filename
    }
}else{
    $sig > $filename
}

#REPLY SIGNATURE
#CHECK IF THERE IS A SIGNATURE AND ITS LAST UPDATE TIME
if(test-path $filename2){
    $sigLastModifiedDate = [datetime](Get-ItemProperty -Path $filename2 -Name LastWriteTime).lastwritetime
    if((get-date $templateLastModifiedDate) -gt (get-date $sigLastModifiedDate)){
        $sig2 > $filename2
    }
    # If an AD change has been made and the created signature is older, then update signature. 
    elseif(($adchangedate) -gt (get-date $sigLastModifiedDate)){
    $sig2 > $filename2
    }
}else{
    $sig2 > $filename2
}

#SET DEFAULT SIGNATURE
$MSWord = New-Object -ComObject word.application
$EmailOptions = $MSWord.EmailOptions
$EmailSignature = $EmailOptions.EmailSignature
$EmailSignature.NewMessageSignature = $un + " (" + $email + ")" #insert the main signature name
$EmailSignature.ReplyMessageSignature = $un + "_reply" + " (" + $email + ")" #insert the reply signature name
$MSWord.Quit()

}

Any ideas?

Many thanks, Matthew

anx avatar
fr flag
anx
A huge script that could fail in multiple places, with no effect besides "works" and "does not work"? Not knowing what sort of environment it gets executed it, I would still say there just has to be a way for it to log/store a little more than just the final result.
M.Atkinson avatar
lb flag
The files and modified template files are reaching the Signature location within Windows Signature location, but the newest version of Office 365 does not pick this up. If I manually create a Signature within office the Files are all there, be it with a couple of extra files (rich text and text formats) as well as the ones created from the script but only the ones manually created appear in outlook. I am confident therefore it's not entirely the script but rather a change within outlook that has stopped the signatures from being pickup up.
M.Atkinson avatar
lb flag
Good morning! Thanks for your comment and honesty, really appreciate. I will add this comment to add a bit more context to the post! Please let me know if I should clarify anything else. Also, I am aware that this could have more logging but also don't... It has been working fine on all versions of Office (Including 365) for quite some time until very recently.
anx avatar
fr flag
anx
Have you unexpectedly enabled [signature setting cloud storage a.k.a "roaming signatures"](https://www.microsoft.com/en-ie/microsoft-365/roadmap?rtc=1&searchterms=60371&filters=&searchterms=60371)?
M.Atkinson avatar
lb flag
Not that I am aware, I haven't research yet but is this a GP setting or would it be something that a user would set themselves? The signatures themselves are saving in the AppData/roaming folder after this script runs as that is the only place where the Signature files are stored. Example local path: C:\Users\USER\AppData\Roaming\Microsoft\Signatures
Score:1
lb flag

Right! I finally got to the bottom of this and what was going on. It was in fact to do with Roaming Signatures in Outlook 365 - a new feature turned on at the beginning of October 2022.

The good news is it can be turned off via registry edit (which can be pushed out via GP if so desired.

Registry location is: HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Setup\

DWORD (32-bit) - Reg name: DisableRoamingSignaturesTemporaryToggle

Modify or double-click DisableRoamingSignaturesTemporaryToggle

and put Value data 1and then Hexadecimal

Click Ok and then Apply.

Full Guide

I hope this helps other people like it helped me.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.