Dynamic Outlook Email Signature Using with Intune Endpoint Analytics Proactive Remediations

Jóhannes Geir KristjánssonAzure, Documentation, Endpoint Management, How-To, Intune, MECM/MEMCM/SCCM, Microsoft, Office, Powershell, Proactive Remediation, Windows3 Comments

Howdy y’all!

Since you have already read señor Shackelfords blog post on setting up Endpoint Analytics Proactive remediations, we can skip the intro and dive right in.

In this blog post we will be get familiar with a somewhat novel idea that proactive remediation’s can be used for. Which, as the title of this post suggests, is the creation of a dynamic email signature in the form of a .html file using Microsoft Graph.

Getting Started

To get started you need to familiarize your self with how to connect to the Microsoft Graph and query for data. Luckily Brad Wyatt has made an excellent blog post on the subject, so go read it before you read the rest of this post. Follow the steps he lists to create a new Azure application. When you get to the Client Credentials section, see below.

Welcome back. Now that we are on the same page, let’s continue. The application we create in Azure needs to be granted the User.Read.All permission. don’t forget to grant consent if prompted.

Note: Setting permissions properly is essential to prevent Azure applications from being exploited. Only grant the minimum rights needed for the app.


Now on to the fun part. We need a discovery script that will checks if the Outlook signature file exists, how old it is and if no file exists, report non-compliance. If the file is older than current day, its also non compliant.

Note the $signatureFileName variable on line 2, you need to decide on the signature name. It can be anything you want.

# must be the same name as the file that is generated by the Remediation script
$signatureFileName = "contoso.htm"

# check if signaturefile even exists
try {
    if ( (Test-Path $env:APPDATA\microsoft\signatures\$signatureFileName -ErrorAction stop) -eq $false) {

        Write-Host "$signatureFileName does not exist"
        exit 1


catch {
    $errmeg = $_.exception.message
    Write-Error $errmeg
    exit 1

# check if the file is out of date
try {
    # check date
    $lastwritetimeday = (Get-ItemProperty -Path "$env:APPDATA\microsoft\signatures\$signatureFileName").LastWriteTime.DayOfYear
    $today = (Get-Date).DayOfYear

    if ($lastwritetimeday -lt $today) {
        Write-Host "signature is out of date"
        exit 1

catch {
    $errmeg = $_.exception.message
    Write-Error $errmeg
    exit 1


Now on to the remediation part. You will need to populate a few variables.

$signatureFileName (same as in the discovery script)

The information required for these can be found in Azure AD in the app properties, as detailed in Brads blog:

Pro Tip: the v1.0 graph will only return a few basic attributes about the user, the beta graph returns a whole lot more.

#Region Microsoft Graph
# must be the same name as specified in the discovery script
$signatureFileName = "Contoso.htm"

# Application (client) ID, tenant Name and secret
$clientId = ""
$tenantName = "contoso.onmicrosoft.com"
$clientSecret = "Hunter2"
$resource = "https://graph.microsoft.com/"
$ReqTokenBody = @{
    Grant_Type    = "client_credentials"
    Scope         = "https://graph.microsoft.com/.default"
    client_Id     = $clientID
    Client_Secret = $clientSecret
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody

# $apiUrl = 'https://graph.microsoft.com/beta/users/7b613445-d1b8-4af3-938b-c08a4e5b1160'

# who is currently logged on to the system
$upn = whoami /upn
$apiUrl = 'https://graph.microsoft.com/v1.0/users/{0}' -f $upn

$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)" } -Uri $apiUrl -Method Get

#EndRegion Microsoft Graph

#Region Variables
# lets put the data into variables so easier placement in the HTML
$displayname = $data.displayName
$jobtitle = $data.jobTitle
$businessphone = $data.businessPhones
$mail = $data.mail
$officelocation = $data.officeLocation
#EndRegion Variables

#Region HTML

# keep in mind that if you use CSS, you need to put it its own here string, as the {} in CSS don't mix well with the -f format operator

$HTML = @' 
<p>displayname: {0} </p>
<p>jobtitle: {1} </p>
<p>phone: {2} </p>
<p>email: {3} </p>
<p>location: {4} </p>
'@ -f $displayname, $jobtitle, $($businessphone), $mail, $officelocation
#EndRegion HTML

#Region Output
# check if the signatures directory exists, if not, create it
if ((Test-Path $env:APPDATA\microsoft\signatures) -eq $false) {new-item -ItemType directory -Name "signatures" -Path $env:APPDATA\microsoft\}

# output the .htm signature file

$html | out-file $env:APPDATA\microsoft\signatures\$signatureFileName -Force

#EndRegion Output


Now you just need to deploy the script package to a group, make sure its set to run with the logged-on credentials and use 64-bit PowerShell. Follow the steps in Jake’s post to create a new script and deploy it.

Once the script package is on a client, the signature will appear in Outlook, though Outlook will not configure it as a default on its own. (perhaps an idea for another blog post).


If you run into any issues or have questions about anything Intune head over to the WinAdmins discord community and go to the #Intune channel, and ask Jake to help you.

3 Comments on “Dynamic Outlook Email Signature Using with Intune Endpoint Analytics Proactive Remediations”

  1. For anyone uncertain of the CSS comment on line 43.
    You can separate the css/style portion of the html file from the rest of the code listed as $html and then combine both of them by simply adding the two together back in line 61.

    $CSS = @’



    $HTML = @’

    displayname: {0}

    jobtitle: {1}

    phone: {2}

    email: {3}

    location: {4}

    ‘@ -f $displayname, $jobtitle, $($businessphone), $mail, $officelocation

    $CSS + $HTML | out-file $env:APPDATA\microsoft\signatures\$signatureFileName -Force

  2. First of all thanks for this guide and the accompanying guides on setting the default email signature. they were instrumental in me getting this running for my group.
    One Item I am lacking for some of my coworkers is that some of our user’s insist on having some of their certs or titles added after their name. Previously we would pull this information through the ExtensionAttributes in AD. I’m assuming this could be done with the beta for MSgraph, but I haven’t been able to find much usable data to give direction on how I could pull that information from Azure. Any guidance or links that detail some of this information would be appreciated.

  3. I wanted to make an update to the comment I left earlier today regarding using extensionattributes in AzureAD, but it doesn’t look like my comment has posted yet.
    I had to go into Azure AD Connect > Configure > Customize syncronization options > Optional Features
    enable “Directory extension attribute sync” and then find and add extensionAttribute1. I also enabled some of the msDS-CloudExtensionAttributes while in there as well. Once I saved my changes and gave the sync process a few minutes to catch up I was able to my information in WindowsPowershell, connected to AzureAD with the following command.
    Get-AzureADUser -ObjectId [email protected] | Select-Object -ExpandProperty ExtensionProperty

    Key Value
    — —–
    odata.metadata https://graph.windows.net/….
    odata.type Microsoft.DirectoryServices.User
    createdDateTime 4/24/1987 3:14:39 AM
    employeeId NA
    onPremisesDistinguishedName CN=DeepFriedLettuce,OU=Users,OU=Lettuce,DC=Fried,DC=com
    [email protected] directoryObjects/….
    [email protected] image/Jpeg
    userIdentities []
    extension_ac71da5151516445494415515151ed8_extensionAttribute5 Randominformation
    extension_ac71da5151516445494415515151ed8_extensionAttribute1 [my certs were listed here]

    My hope is to add this information into my script with the following command:
    (Get-AzureADUserExtension -ObjectId [email protected]).get_item(“extension_ac71da5151516445494415515151ed8_extensionAttribute1”)

    If I’m able to, I’ll follow up with my results.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.