All posts by Jos

Automated Stale Device Cleanup in Azure Active Directory using a runbook

As with cleaning up inactive guest users, inactive devices also pose several issues for organizations.

Microsoft recommends cleaning up stale devices after 90 days, but does not provide a service option or automation to do so.

Therefore, another runbook you may run to just report on your inactive devices, or to automatically (and optionally periodically) clean up inactive devices in your environment when the removeInactiveDevices switch is supplied.

Managed identity

When run locally, interactive sign in is required. When running as a runbook in Azure automation, the Managed Identity of the automation account is leveraged. This requires you to set Device.ReadWrite.All or Device.Read.All permissions depending on if you want to script to do the cleanup as well.

Autopilot / on premises devices

Note that the script will log an error (and not attempt to delete the device) when a device is an autopilot record (not a real device) or when the device is synced from an on-premises active directory.


Download get-AzureADInactiveDevices.ps1 from Gitlab


As always, the script is provided as-is and should be reviewed and then used at your own risk.

Guest User Last Sign-in date time in Azure Active Directory and automatic cleanup

Azure AD’s sign in logs also only go back 30 days, which makes it highly recommended to stream Azure AD’s sign in logs to a Log Analytics workspace (Azure Monitor). You just need one single P1 license in your tenant to be able to enable this.

However, even if you don’t stream your sign in logs, Microsoft does keep track of when an account last signed in.

My script gets the last sign in data of all guest accounts in your tenant, without any dependencies other than the Az PS module.

If a guest user has never signed in, the creationDate is used to determine inactivity. Otherwise either the last interactive or last non interactive sign in is used (whichever is most recent).

Additionally, the script can also be configured to automatically clean up any guest accounts that have been inactive for a given number of days by using the -removeInactiveGuests switch.

Even in large environments, processing only takes a few minutes at most.


Download the script from my Gitlab here:


Microsoft started using these properties in april 2020, so accounts active before that will seem like they have never been active.


This script supports running non-interactive as a runbook in Azure Automation if you supply the -nonInteractive switch. Before this will work, you’ll have to enable Managed Identity on your automation account and run a small script to assign graph permissions to the Managed Identity: AuditLog.Read.All and Organization.Read.All


As always this script is provided as-is and should be reviewed and then used at your own risk.

Onedrive for Business sync error monitoring and auto remediation

With the introduction of Onedrive Sync Heath in the Office portal, we have a much improved view on sync errors of our users. Errors they may not even be aware of.

However, there is no remediation option, so I am sharing a framework based on previous work in Proactive Remediations that can report on the Onedrive client status and trigger a remediation, which looks like this:

Currently, the only remediation method is to restart the Onedrive client, but the script is easily adjusted for additional remediation actions or conditions the community deems useful.

When Paused or Disabled are detected, there is no remediation as this is not technically an error but something the user manually set. This can be adjusted to your local needs easily.

You can find the Proactive Remediation script on Gitlab:

To use it, follow the steps in my previous article using proactive remediations (LAPS).

the only difference with LAPS config is that the script should run in user context:

The detection and remediation scripts are the same, the script is smart enough to detect if it is running in detection or remediation mode.

Credits go to Rudy Ooms for writing about the different status codes of the Onedrive client 🙂

Convert FSLogix profile to local profile

FSLogix, the defacto profile management solution for Azure Virtual Desktop, allows you to easily roam profiles between different Azure Virtual Desktops.

A solution to convert profiles to FSLogix profiles is available, but for the reverse, I couldn’t find anything.

In some situations, e.g. dedicated VDI’s, a local profile may perform better and reduce infrastructure complexity (no share required). Especially in larger environments with thousands of VDI’s the required performance of the profile share is very high.

I wanted to test converting / migrating back from FSLogix profiles to local profiles on a specific machine, which resulted in a simple PowerShell script that can be executed using Run Command or by an admin on the VM.

It mounts the profile of a given user, copies the data to the local VM, unmounts the profile (so the profile is not deleted!) and sets a bunch of registry keys to properly connect the local profile and disable FSLogix roaming on that VM for that user.

See GitLab

Ghost Mailusers

We had an odd case today that Msft support hasn’t fixed yet, but in case someone googles the error and finds this, I did find a workaround.

We had a MailUser object that was inactive (soft deleted), but couldn’t be permanently deleted using

Remove-MailUser -PermanentlyDelete -Identity $mailuser.ExternalDirectoryObjectId

The resulting error was:

This mail enabled user cannot be permanently deleted since there is a user associated with this mail enabled user in Azure Active Directory. You will first need to delete the user in Azure Active
Directory. Please refer to documentation for more details.

However, nothing was found in AzureAD (or deleted users/recycle bin), and nothing was present in our on-prem AD.

This user was deleted a long time ago, and now being rehired….but account creation was being blocked because the mail user was still claiming the email address of this user.

After some messing around, and not patiently waiting for Msft 1st line support to delete this corrupted MailUser, I discovered the RecalculateInactiveMailUser switch in the set-MailUser command.

Normally, you can’t modify the primary smtp / aliases of a soft deleted mailuser or mailbox….BUT, for some reason, if you supply RecalculateInactiveMailUser you can. So:

Set-MailUser -Identity $mailuser.ExternalDirectoryObjectId -EmailAddresses $newProxies -RecalculateInactiveMailUser

Worked fine! While

Set-MailUser -Identity $mailuser.ExternalDirectoryObjectId -EmailAddresses $newProxies

Failed with

The operation couldn’t be performed because object ‘270fc89f-0424-42d2-8f54-25796f74457b’ couldn’t be found on ‘DB8PR02A05DC001.EURPR02A005.PROD.OUTLOOK.COM’.