Proactive Remediations 101 – Intune’s hidden secret!

As I’m sure some of you know, I’m a big fan of Powershell scripting and find most tasks can be done far more quickly with a script than manually.

Whilst the Powershell scripts within Intune work nicely, they are run-once scripts (unless you want to start deleting registry keys) and sometimes you want a script which runs regularly.

This is where Proactive Remediations fits in nicely, think of it as Scheduled Tasks for Intune (but with some added logic), but they can be difficult to get your head around at first so I’ll go through how they work and the steps involved in this post.

Firstly, if you’ve never used them before, you’ll find them hidden in the Reports Menu (Reports – Endpoint Analytics – Proactive Remediations):

The first time you load it, you’ll have to confirm you are licensed to use it, I’m assuming if you’re reading this that you must be.

Once inside, it’s split into 3 sections: Detection Script, Remediation Script and Assigment (which includes how often it runs)

Detection Script

This is the logic that decides if the second remediation script will run or not and it can be absolutely anything you can query with powershell.

What you are looking at here are the exit codes. If Intune is given an exit code of 0, it will NOT run the remediation script, this is a clean exit and the machine has (or doesn’t have) whatever you are looking for.

On the other hand, if it finds the exit code is 1, this will trigger the next script to run.

For example, if I’m looking for a particular registry key (in this case fastboot), the script will look like this:

$Path = "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power"
$Name = "HiberbootEnabled"
$Type = "DWORD"
$Value = 0

Try {
    $Registry = Get-ItemProperty -Path $Path -Name $Name -ErrorAction Stop | Select-Object -ExpandProperty $Name
    If ($Registry -eq $Value){
        Write-Output "Compliant"
        Exit 0
    Write-Warning "Not Compliant"
    Exit 1
Catch {
    Write-Warning "Not Compliant"
    Exit 1

At the top we just set what we are expecting to see in a good machine.

Then we check if the registry key exists at all with the Try code block. Obviously if it doesn’t exist, we catch the error and error out with a code 1:

 Write-Warning "Not Compliant"
    Exit 1

If the key exists, we then query the value of it to make sure it matches what we are looking for. If we find a match, exit with a code 0, that machine is fine and does not require anything else to run. If the value doesn’t match, we need to sort that!

Registry key is just one example though, we could also use:

Does a file exist?

$File = "C:\windows\system32\notepad.exe"
if (!$file) {
    write-host "Not found"
    exit 1
else {
    write-host "Found"
    exit 0

Or machines which haven’t rebooted in the last 3 days:

$uptime = get-uptime
if ($uptime.days -gt 3) {
    write-host "Not rebooted in last 3 days"
    exit 1
else {
    write-host "All fine, recently rebooted"
    exit 0

I’m sure you get the idea!

Remediation Script

This is the part which actually fixes whatever you were initially looking for. We don’t have to worry about exit codes for this one, it runs regardless.

Logging can be found in the Intunemanagementextension.log file, but for ease, I prefer to add my own logging via the start-transcript functionality. I often add the same logic into the remediation script as well just to be extra careful, all it takes is one typo in the detection and it could remediate everything!

So in the case of the fastboot, we simply set the reg key:

Start-Transcript -Path $env:TEMP\DisableFastBoot.txt
if((Test-Path -LiteralPath "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power") -ne $true) {  
  write-host "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power does not exist"
  New-Item "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power" -force -ea SilentlyContinue
write-host "Key Created" };
New-ItemProperty -LiteralPath 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power' -Name 'HiberbootEnabled' -Value 0 -PropertyType DWord -Force -ea SilentlyContinue;
write-host "Value Set"


For the missing file, we could download it from GitHub/Azure Blob etc.

Start-Transcript -Path $env:TEMP\copyfile.log
$File = "C:\windows\system32\notepad.exe"
if (!$file) {
    write-host "File not found, downloading"
$fileurl = ""

#Set the download location
$output = "c:\my.location\"

#Download it
Invoke-WebRequest -Uri $appurl -OutFile $output -Method Get
write-host "file downloaded to $output"

Or for the machine that hasn’t restarted, we could force a reboot

shutdown /t 300 /r /c "Your machine will restart in 5 minutes, please save any work now"


Once your scripts are created and tested, the next step is to assign them to a group, all users etc.

Once assigned, navigate back to the assignment screen and you can see your options for scheduling (and filtering if required)

Your options here are:

Once (specify date and time)
Hourly (specify how many hours apart between runs)
Daily (specify how many days apart and at what time)

Hopefully that has taken some of the mystery away and everyone will start to use this excellent feature! If there are any particular remediations you want me to add code for, just let me know in the comments.

Posted in Intune