Troubleshooting and Logging Intune Remediations

dwight

Over the last few months, I’ve done a ton of work with Intune Remediations. I wrote about renaming Windows Devices last month and last year I wrote about the new unified logging for Win32 Apps. While working on an issue recently, I learned that documentation around troubleshooting when remediations aren’t doing their remediating was lacking. Today, we’re going to cover:

Properly Writing Intune Remediation Scripts

First, we’ll backup and discuss how remediation works. Some of the basics:

  • You can have up to 200 of them.
  • Packages consist of a detection script OR a detection and remediation script (aka you can put it all into one if you want to)
  • Remediations only run if the detection evaluates with exit code “exit 1”
  • You can run them as 32-bit or 64-bit.
  • You can run them as system or the current logged on user
  • You can also enforce script signing if you want
  • Avoid reboots, sensitive info, PII, and just overall don’t do bad things.

Many typical detection scripts will look like this:

# Variables for registry path and property name
$registryPath = "HKLM:\SYSTEM\CurrentControlSet\Services\tzautoupdate"
$propertyName = "Start"
 
# Check the current registry value
$currentValue = Get-ItemProperty -Path $registryPath -Name $propertyName
 
# Check if automatic time zone detection is disabled
if ($currentValue.Start -ne 3) {
    # Return non-compliant status
    Exit 1
} else {
    # Return compliant status
    Exit 0
}

So, you think cool it has exit 1, so it works right? Yeah, it sorta works (as in it does functionally work, but is it a good idea?) Something that came more obvious to me lately was the need to expand on what a script is actually doing.

A very simple thing we can do is simply add this:

Start-Transcript -Path "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneRemediations.log" -Append
# Variables for registry path and property name
$registryPath = "HKLM:\SYSTEM\CurrentControlSet\Services\tzautoupdate"
$propertyName = "Start"
 
# Check the current registry value
$currentValue = Get-ItemProperty -Path $registryPath -Name $propertyName
 Write-Host "The current value is $currentValue"
# Check if automatic time zone detection is disabled
if ($currentValue.Start -ne 3) {
    # Return non-compliant status
    Write-Output "NonCompliant"
    Exit 1
} else {
    # Return compliant status
    Write-Output "Compliant"
    Exit 0
}

That code will ensure that a running log is kept of all of your commands and is written to a special IntuneRemediations Log file inside of the IME folder. We do this so that if you collect device diagnostics it will come down with it. One caveat is that if its being run as the current logged on user, you would need to write to something like C:\temp or whatever your folder of choice is.

Inevitably, writing PowerShell is an artform. You can be as basic or as creative as you want to be. If it works, who cares? I know many people are a bit pretentious about code, but it’s good code if it works for you. Overall, the main takeaway is make sure you are outputting results of things in your scripts, which is useful when you check out the console as well.

Reviewing Local Logs on Test Devices

It might not be completely obvious, so I find it really useful to call it out. When you work with remediations, the log file is:

C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\AgentExecutor.log

Sometimes if I’m being lazy I don’t use start transcript because Agent Executor collects basically the same data.

Let’s check it out. First, the logs for the detection script are below. It shows you the path of the script, the command line with arguments that is run and will even show you the write-output and the exit code:

]LOG]!><time="11:30:30.0508084" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Revert Wow64FsRedirection]LOG]!><time="11:30:30.0514760" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[ExecutorLog AgentExecutor gets invoked]LOG]!><time="11:31:31.1864422" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Creating command line parser, name delimiter is - and value separator is  .]LOG]!><time="11:31:31.1894441" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Getting Ordered Parameters]LOG]!><time="11:31:31.1894441" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Parsing Ordered Parameters.]LOG]!><time="11:31:31.1904440" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Adding argument remediationScript with value C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\detect.ps1 to the named argument list.]LOG]!><time="11:31:31.1904440" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[remediation script option gets invoked]LOG]!><time="11:31:31.1904440" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\detect.ps1]LOG]!><time="11:31:31.1904440" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\b564d875-3991-4ec9-a695-1f080c8be583_PreDetectScript.output]LOG]!><time="11:31:31.1904440" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\b564d875-3991-4ec9-a695-1f080c8be583_PreDetectScript.error]LOG]!><time="11:31:31.1904440" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\b564d875-3991-4ec9-a695-1f080c8be583_PreDetectScript.timeout]LOG]!><time="11:31:31.1904440" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\b564d875-3991-4ec9-a695-1f080c8be583_PreDetectScript.exit]LOG]!><time="11:31:31.1904440" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Prepare to run Powershell Script ..]LOG]!><time="11:31:31.1924424" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[scriptParams is ]LOG]!><time="11:31:31.1924424" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[cmd line for running powershell is -NoProfile -executionPolicy bypass -file  "C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\detect.ps1" ]LOG]!><time="11:31:31.1924424" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[runAs32BitOn64 = False, so Disable Wow64FsRedirection]LOG]!><time="11:31:31.1924424" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[PowerShell path is C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe]LOG]!><time="11:31:31.1924424" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[[Executor] created powershell with process id 36012]LOG]!><time="11:31:31.2014483" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Powershell exit code is 1]LOG]!><time="11:31:37.5288159" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[lenth of out=64]LOG]!><time="11:31:37.5288159" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[lenth of error=2]LOG]!><time="11:31:37.5288159" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[error from script =
]LOG]!><time="11:31:37.5288159" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Powershell script is failed to execute]LOG]!><time="11:31:37.5288159" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[write output done. output = SMB port 445 is open on 192.168.1.30. Exiting with status 1.

Now, if we check out the attempt at remediation below it’s also pretty neat. It will show all of the things that I outputted from my script and even the exception that I hit (because the logged in credentials are invalid):

]LOG]!><time="11:31:37.5308153" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Revert Wow64FsRedirection]LOG]!><time="11:31:37.5308153" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[ExecutorLog AgentExecutor gets invoked]LOG]!><time="11:31:42.6400562" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Creating command line parser, name delimiter is - and value separator is  .]LOG]!><time="11:31:42.6430562" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Getting Ordered Parameters]LOG]!><time="11:31:42.6430562" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Parsing Ordered Parameters.]LOG]!><time="11:31:42.6430562" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Adding argument remediationScript with value C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\remediate.ps1 to the named argument list.]LOG]!><time="11:31:42.6430562" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[remediation script option gets invoked]LOG]!><time="11:31:42.6440555" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\remediate.ps1]LOG]!><time="11:31:42.6440555" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\a9b01e74-8f63-47c2-8886-e13f4c5a3d2c_RemediationScript.output]LOG]!><time="11:31:42.6440555" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\a9b01e74-8f63-47c2-8886-e13f4c5a3d2c_RemediationScript.error]LOG]!><time="11:31:42.6440555" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\a9b01e74-8f63-47c2-8886-e13f4c5a3d2c_RemediationScript.timeout]LOG]!><time="11:31:42.6440555" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\a9b01e74-8f63-47c2-8886-e13f4c5a3d2c_RemediationScript.exit]LOG]!><time="11:31:42.6440555" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Prepare to run Powershell Script ..]LOG]!><time="11:31:42.6450560" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[scriptParams is ]LOG]!><time="11:31:42.6460560" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[cmd line for running powershell is -NoProfile -executionPolicy bypass -file  "C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\remediate.ps1" ]LOG]!><time="11:31:42.6460560" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[runAs32BitOn64 = False, so Disable Wow64FsRedirection]LOG]!><time="11:31:42.6460560" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[PowerShell path is C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe]LOG]!><time="11:31:42.6460560" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[[Executor] created powershell with process id 40380]LOG]!><time="11:31:42.6540554" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Powershell exit code is 0]LOG]!><time="11:31:43.1938125" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[lenth of out=169]LOG]!><time="11:31:43.1938125" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[lenth of error=515]LOG]!><time="11:31:43.1938125" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[error from script =New-PSDrive : The specified network password is not correct
At C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_7\remediate.ps1:36 char:1
+ New-PSDrive -Persist -Name "Z" -PSProvider "FileSystem" -Root $networ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (Z:PSDriveInfo) [New-PSDrive], Win32Exception
    + FullyQualifiedErrorId : CouldNotMapNetworkDrive,Microsoft.PowerShell.Commands.NewPSDriveCommand
 

]LOG]!><time="11:31:43.1938125" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Powershell script is successfully executed.]LOG]!><time="11:31:43.1938125" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[write output done. output = The UPN is [email protected]
The username is jjtowles
The network path is \\192.168.1.30\personal\jjtowles
Drive Z: mapped to \\192.168.1.30\personal\jjtowles

The reason this is super useful is when you iterate. We’re going to cover that later on when we look at how to get the actual result you’re looking for.

Reviewing Remediation Logs in the Intune Console

You would expect that reviewing logs is no big deal. Sadly, it’s a bit annoying because you have to modify columns and all that nonsense.

Once you go into Devices > Scripts and Remediations you drill into the package you’re interested in:

screenshot of the remediations page in Intune

Once you drilldown into a package, you click on Monitor > Device Status. Sadly, you will notice it’s not super useful:

Screenshot of the monitor/device status page on a remediation package

By clicking on the columns section, you can get the output of your write commands to see what went wrong exactly:

the different columns available on a remediation for the monitor page

Now, I can see that my detect script exited 1 like I hoped it would:

screenshot of the pre-remediation detection output

Iterative Testing of Intune Remediations

Now, let’s discuss why all of this is so important. When we look at scripts, we have different options that are sometimes important in their own way:

screenshot of different options you can use in remediations like 64-bit PowerShell or running the script as the logged-on user.

Specifically, does a particular script need to be run as system or the current user? Does it require 64-bit PowerShell? Those answers are only possible by writing proper inputs because often what you test on your local machine manually doesn’t correlate to what happens when it comes down from Intune via the Intune Management Extension.

Here’s a great real-world example of testing and looking at my output. Below, the output will show you that basically I was running as 32-bit PowerShell and the code I wrote to pull the username was not actually pulling the username for whatever reason:

]LOG]!><time="11:27:02.9162016" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Powershell script is successfully executed.]LOG]!><time="11:27:02.9162016" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[write output done. output = The UPN is 
The username is 
The network path is \\192.168.1.30\personal\
Drive Z: mapped to \\192.168.1.30\personal\

, error = New-PSDrive : Access is denied
At C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_5\remediate.ps1:36 char:1
+ New-PSDrive -Persist -Name "Z" -PSProvider "FileSystem" -Root $networ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (Z:PSDriveInfo) [New-PSDrive], Win32Exception
    + FullyQualifiedErrorId : CouldNotMapNetworkDrive,Microsoft.PowerShell.Commands.NewPSDriveCommand

That helped me realize that I needed to switch to 64-bit PowerShell.

I ran it again and made another discovery thanks to the logs! I realized that I can’t run this as system because system wouldn’t be able to authenticate to a user’s personal drive (had to switch this to the current logged on user):

]LOG]!><time="11:30:30.0495200" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[Powershell script is successfully executed.]LOG]!><time="11:30:30.0495200" date="2-22-2025" component="AgentExecutor" context="" type="1" thread="1" file="">
<![LOG[write output done. output = The UPN is [email protected]
The username is jjtowles
The network path is \\192.168.1.30\personal\jjtowles
Drive Z: mapped to \\192.168.1.30\personal\jjtowles

, error = New-PSDrive : Access is denied
At C:\WINDOWS\IMECache\HealthScripts\97140e99-373b-4d2b-9f44-8e15ddada46e_6\remediate.ps1:36 char:1
+ New-PSDrive -Persist -Name "Z" -PSProvider "FileSystem" -Root $networ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (Z:PSDriveInfo) [New-PSDrive], Win32Exception
    + FullyQualifiedErrorId : CouldNotMapNetworkDrive,Microsoft.PowerShell.Commands.NewPSDriveCommand
 

Our main takeaway overall is that by using mindfulness in your PowerShell scripts and reviewing logs while you build/test remediation scripts, you can cut down on development times and stop trying to firefight in the dark.

Below is a short video demo on that whole process and how doing things correctly is really useful.

Facebook
Twitter
LinkedIn
The post discusses the author's experience with Intune Remediations, highlighting the importance of well-crafted remediation scripts and thorough logging. Key topics include proper script writing, local log reviews, and log monitoring within the Intune Console. The author emphasizes an iterative testing approach to enhance script efficacy and reduce troubleshooting efforts.

5 thoughts on “Troubleshooting and Logging Intune Remediations”

  1. sridhar jilkar

    Will remediation Scott rerun on without issue machines.
    If answer is know how do re trigger script

  2. How often the detect script will run? I would like to run dism /online /cleanup-image /scanhealth every 180 days.

Leave a Reply to Michal HajduchCancel reply

Scroll to Top

Discover more from Mobile Jon's Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading