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, WindowsLeave a Comment

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.

Leave a Reply

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