Saving e-mail from Exchange Online to the filesystem using Microsoft Graph

At a recent work related conference, where for a change of pace I was helping out on a IT Helpdesk, I was asked by someone if there was an easy way to save emails from Outlook to their OneDrive account.

While this is a relatively easy task for small numbers of emails where you can drag and drop them to a synced OneDrive folder on the local desktop, in this case they had a full folder structure of emails which had grown out of necessity and time restrictions and it isn’t possible to drag and drop folders in the same way.

Now, the obvious thought was to use the export function from Outlook, but this results in a PST-based mail archive and this wasn’t what the requestor wanted.

Now, over the last year I have been increasingly using the MSGraph PowerShell module to rewrite a lot of my scripts which had been using now deprecated libraries, so I thought this would be worth a go.

Unsurprisingly, MS Graph again came to the rescue and I thought (despite this being a bit of a niche requirment) I would share the resulting script at https://github.com/imnota/export-emailsToFiles

To use the script, you need delegated permissions on the target mailbox and Mail.Read.Shared permissions on Graph.

The script will find the first occurrence of the folder name you specify and recursively save folders of emails under that folder (duplicate starting folder names will be looked into when I have a little more time).

It’s relatively simple to use, as can be seen in this example:

.\Export-emailsToFiles.ps1 -userPrincipalName joe.bloggs@example.domain.com -emailFolderName "Inbox" -fileFolderRoot C:\EmailExtract

Of course, if you have a synced OneDrive folder you want to extract to, you can use that in the “fileFolderRoot” parameter.

While the script may not be perfect, hopefully it will prove useful to someone out there!

Using Proactive Remediations to Update Office

Well, it’s been a busy few months. Just when you think that things have got to start quietening down, an issue like the Outlook NTLM Vulnerability (CVE-2023-23397) pops up.

So, what can you do if you have over 1,000 remote devices to update, and are worried that office automatic updates aren’t working fast enough to get the job done and you aren’t using the Microsoft Apps admin center to manage the Monthly Enterprise Channel?

This is where Proactive Remediations in Microsoft Intune can be useful.

Before we look at creating the remediation package, we need to create two scripts

The Scripts

The below two scripts will work for Office installations which are installed using ClickToRun.

First create a script to detect the issue and save it as something like “DetectOldOffice.ps1”

# Written to detect if Office is affected by CVE-2023-23397 - Outlook NTLM flaw
# Validate whether Click2Run.exe has a modifed date >= 15/03/2023
#
# We cannot easily check office version numbers as the patched version differs across multiple
# channel versions, and is not numerically subsequent to unpatched versions (aside from within that channel)

$notUpdatedAfter=[datetime]"2023-03-15"

try {
    $c2r=get-item "$($Env:ProgramFiles)\Common Files\microsoft shared\ClickToRun\OfficeC2RClient.exe"
    if($c2r.CreationTime -lt $notUpdatedAfter) {
        write-output "OUTOFDATE: OfficeC2RClient ($($c2r.versioninfo.FileVersion)) is old with a date of $($c2r.creationtime)"
        exit 1
    }
    else {
        write-output "All Good: OfficeC2RClient ($($c2r.versioninfo.FileVersion)) has a date of $($c2r.creationtime)"
        exit 0
    }
}
catch {
    write-output "Office Click2Run not found!"
    exit 0
}

The first script looks at OfficeC2RClient.exe and checks if it was created before the date set in $notUpdatedAfter. If it is older than this, it exits with a return value of “1” which indicates that the remediation script should be run. (You can change this date to any value you want if you have any future needs to update Office.)

Then create another script which will be used to run the ClickToRun client and save it as “UpdateOfficeForCVE2023-23397.ps1”

# Written to run ClickToRun if Office is affected by CVE-2023-23397 - Outlook NTLM flaw
$notUpdatedAfter=[datetime]"2023-03-15"

try {
    $C2R=get-item "$($env:ProgramFiles)\Common Files\microsoft shared\ClickToRun\OfficeC2RClient.exe"
    if($c2r.CreationTime -lt $notUpdatedAfter) {
        #OK, so we need to get the current click2run process so we do not confuse the launched one with the preexisting one
        $initialProcesses=get-process -name "OfficeClickToRun"
        write-output "Spawning update as OfficeC2RClient ($($c2r.versioninfo.FileVersion)) is old with a date of $($c2r.creationtime)"
        $newProcess=start-process -FilePath "$($env:ProgramFiles)\Common Files\microsoft shared\ClickToRun\OfficeC2RClient.exe" -argumentlist "/update user forceappshutdown=false displaylevel=true" -passthru -wait
        #sleep a little to allow it to start
        start-sleep -seconds 60
        #Get the new process (if it exists)
        $spawnedProcess=(get-process -name "OfficeClickToRun"|where {-not($_.id -in $initialProcesses.id)})
        if ($spawnedProcess) {
            wait-process $spawnedProcess.id
        }
        #Keeps being reported as recurring in proactive remediations - maybe we're exiting too fast?
        start-sleep -seconds 60 
        $C2RAfter=get-item "$($env:ProgramFiles)\Common Files\microsoft shared\ClickToRun\OfficeC2RClient.exe"
        write-output "Post Update: OfficeC2RClient has version of ($($c2rafter.versioninfo.FileVersion)) with a date of $($c2rafter.creationtime)"

        exit 0
    }
    else {
        write-output "All Good: OfficeC2RClient ($($c2r.versioninfo.FileVersion)) has a date of $($c2r.creationtime)"
        exit 0
    }
}
catch {
    write-output "Office Click2Run not found!"
    exit 0
}

This script will run the OfficeC2RClient to update Office. In this case we have set forceappshutdown=false and displaylevel=true as we want the end user to see the update process and be prompted to save any work before the updates complete.

The Remediation Package

The next step is to create the remediation package

You can find Proactive Remediations in the Intune Admin Center

Click on Reports, then Endpoint analytics

Then choose Proactive remediations and Create script package

Enter a name for the script package and click next

Click the “Select a file” button for the Detection script file, browse to and select the first script you saved (DetectOldOffice.ps1)

Click the “Select a file” button for the Remediation script file, browse to and select the second script you saved (UpdateOfficeForCVE2023-23397.ps1)

Then click “Next”

While you could use scope tags, in this example we’ll skip past them.

In assignments you can choose to assign to a group, but in this case we’ve assigned to “All devices”

Then click “Next” and on the last screen click “Create”

Roll-out

Now your script package is rolling out to devices you can monitor it by clicking the script in the list of Proactive Remediations.

Although the script is working, you may see that a number of devices report as having the issue recurring. At present I have not been able to resolve this, but have confirmed that Office is being updated on these devices.

You may also see some remediations reporting as failed – in general these tend to be the remediation running past its maximum runtime of 1 hour, possibly due to the user not allowing it to finish the update in this timescale.

So, hopefully this post at least gives you some ideas on how you could use remediation packages to push a near-immediate update to Office. You can look at Microsoft’s tutorial on Proactive Remediations for more information on using this method.

Fixing Intune Management issues when you can’t use Intune

During a recent new application rollout we discovered we had an issue where our Intune managed devices had stopped communicating with Endpoint.

While the team started using Rudy Ooms excellent blogs and intunesyncdebugtool to try to resolve the issue on individual machines, we placed the requisite call to our MS Partner (Transparity) to see if we could discover the root cause.

During our call with Transparity support we discovered the issue was due to our Aruba WiFi Intune integration (historically) requiring a certificate with the Intune Device ID as the subject name, which was conflicting with Intune’s own device certificate as can be seen below.

With a little research we found that since the WiFi config was originally set up Aruba have added the option of using a URI in a SAN for integration instead of using the device id in the subject name as previously required, and Microsoft have updated their documentation to more or less say “don’t use the Intune Device ID as the subject name!”

But where does that leave anyone if their entire estate is dropping out of (or has already dropped out of) management?

Fortunately with a little bit of Powershell script using Defender for Endpoint APIs and LiveResponse it is possible to delete the remote certificates remotely at scale.

Leveraging the APIs in our environment resulted in over 150 machines coming back under management without the need to manually remediate each device.

Sample code and documentation is available on GitHub.