Blocking Office Macros, Managing Windows & macOS via Intune
How to centrally manage essential security settings of self-managed devices
This is a guest post by Martin Kretzschmar, customer success engineer at vast limits, the uberAgent company.
One thing I especially like about my everyday working life is the flexibility it offers. I appreciate the freedom of choice in terms of location, time and device. We want to avoid getting into micro-management but, being an IT company, we also need to provide the necessary security where needed.
One thing that came to my mind recently is the persistent danger posed by Microsoft Office macros or, to be more precise, the execution of VBA code. In this blog post, I will cover how we ensure that the execution of VBA code is disabled on (mostly) self-managed devices.
Given that sophisticated spear-phishing attacks are increasingly targeting specific individuals or organizations we wanted to completely block the execution of macros in Office documents on all devices. This configuration had to be centrally managed, of course, for an array of endpoints running both Windows and macOS.
Since we already used Microsoft Azure Active Directory, e.g. as an identity provider, choosing Intune for configuration management was a logical next step. Intune can be used to manage both Windows and macOS, and it does not require traditional Active Directory domain joins.
Preparing Microsoft Intune
As mentioned, we were already using Azure AD, and because of that some preparation steps, such as setting up a domain name, were not necessary for us. However, you can find a complete list of prerequisites here.
To enable users to join their Windows 10 devices to AAD the MDM user scope needs to be set to
In Intune, certain actions like PowerShell scripts (more on that later) can only be assigned to groups. To avoid having to constantly monitor and edit the memberships of such a group, we make use of dynamic groups. In our case, it was necessary to automatically have all Windows 10 devices in one group. This can be achieved with an advanced rule.
Our advanced rule is defined as:
(device.deviceOSType -eq "Windows") -and (device.deviceOSVersion -startsWith "10").
In addition to Windows we also have macOS devices to cover. To manage these, you first need an MDM push certificate issued by Apple. Push certificates can be requested at the Apple Push Certificates Portal. They have a validity of one year. The necessary CSR is available within the Intune Portal.
Setting Up the Configuration With Device Profiles
Similar to the classic Group Policy objects, Intune also offers the possibility to assign administrative templates to users or devices (depending on the setting).
For our case,
Disable all without notification is assigned to all users. It is worth checking the list of available settings regularly as Microsoft is constantly adding new ones.
Apple devices can be centrally managed using Apple Profile Manager, which is part of macOS Server. However, macOS Server is not required. Profiles are basically just XML files that can be created manually with the information provided by Apple and Microsoft. It is much more comfortable, though, to make use of the ProfileCreator project and follow the instructions in their wiki.
Once created, save the profile in the
mcx format with a
*.mobileconfig extension to make it readable by third-party MDM products like Intune. Then create a custom device configuration profile for macOS and upload the config.
Configuring macro settings is supported on Microsoft Office for macOS 15.33.0 and later. The administrative template only shows Microsoft Office 2016, but versions 2019 and 365 are covered, too.
Beyond AAD Accounts
macOS is protected by a system-wide profile, and templates for Windows devices are applied for every AAD user. So we have all of our Windows and macOS devices secured and are done here, right? Well, not quite.
The previously created Windows templates only apply on a user level. This means that the settings will only be enforced if the logon is actually performed by an AAD user. Local accounts are not affected. That was not acceptable to us. In order to enforce settings for local accounts, too, we used a two-step approach.
Step One: PowerShell
We use Intune’s ability to assign PowerShell scripts to devices. Please make sure that your devices are AAD joined, just registering them is not sufficient. This is crucial to make the following work.
As soon as the script is assigned to the dynamic group we created earlier, the EnterpriseDesktopAppManagement CSP (which is part of Windows 10) will automatically install an app called Microsoft Intune Management Extension. The Intune Management Extension is, amongst other things, responsible for executing our script.
This capability has been available since Windows 10 1607. You can check for the presence of the app in several ways:
- A running Windows service called
Microsoft Intune Management Extension
- The existence of the program path
C:\Program Files (x86)\Microsoft Intune Management Extension
- The presence of
Microsoft Intune Management Extensionin Programs and Features
If you are interested in the details of what the extension is doing exactly, take a look at the log files here in
Scripts are downloaded to
C:\Program Files (x86)\Microsoft Intune Managment Extension\Policies\Scripts, but everything will be cleaned up after execution. The results for each user and script are available in the registry
Please note that every script’s content will be written to the log file in plain text. So make sure not to store any sensitive information within your scripts.
The Intune Management Extension will regularly check for new policies every 60 minutes. There is no way to modify this besides restarting the service.
We are using a PowerShell script to create a scheduled task in the local machine context. It will be executed once an hour, when a user logs on, or when the workstation is unlocked.
This scheduled task executes a script if one of these triggers are fired. The script itself is pushed to the device using another technique.
Step Two: Win32 Apps
Unlike traditional Group Policy, Intune, unfortunately, does not have the capability of a simple file copy to managed devices. Again, we utilize the previously installed Intune Management Extension, but this time for deploying Win32 apps (documentation).
Apps need to be packaged in the
*.intunewin file format and this is accomplished by using the Microsoft Win32 Content Prep Tool.
In order to “deploy” our script, we now need an install and uninstall routine. The easiest way is via two small batch files:
REM (Create folder and) Copy Script IF NOT exist "%ProgramData%\vast limits\" (mkdir "%ProgramData%\vast limits\") copy vl.ComplianceSettings.ps1 "%ProgramData%\vast limits\vl.ComplianceSettings.ps1" /Y
REM Delete Script del /f "%programdata%\vast limits\vl.ComplianceSettings.ps1"
The creation of the package is quite simple. You only have to specify the folder with the source files and the executable for the installation itself. The Win32 Content Prep Tool creates a packaged
*.intunewin file that can be uploaded to Intune as type
Windows app (Win32).
For the assignment, we use our dynamic Windows devices group once more. The script itself will perform several tasks:
- Disable Microsoft Office macro execution by querying all currently logged on users and setting the appropriate registry values under
- Disable Microsoft Office DDE execution (documentation)
- Disable web search in start menu by modifying the
The Intune service needs to somehow identify a successful installation and presence of an application. Even though we are basically just putting a text file somewhere, the
Detection Rules are limited. Our implementation looks like this:
Only if all requirements are met, the presence of the application is set to
true. Otherwise, the application will be (re-)installed. This comes in handy if the script gets deleted or modified (accidentally or not).
Registry information related to applications is located at
All scripts described in this article are available for download at the vast limits GitHub repository.
That concludes our implementation. Let me know what you think about it in the comments below.