Check Intune Powershell script result with Graph API

Are you using the option of executing Powershell scripts on your Windows machines using Intune? I find them quite useful in case something you want to accomplish isn’t natively available by using Configuration Profiles or custom CSPs. For example, deploying an configuration for one of the apps in your environment.

However, although it is easy and convenient to deploy scripts using Intune, actual result of the script execution presented in the GUI is rather poor – you are usually going to be presented with either “Succeeded” or “Failed” result. In cases with complex scripting that message might not be enough since such scripts can “fail” at different steps and you might be interested at which point did it exactly failed in order to provide further troubleshooting steps.

With poor reporting on the GUI side, you’re left with reaching to your local IT support to provide you with log results which might be written by your script (by using Start-Transcript or Write-Output cmdlets or custom functions such as Write-Log), however this involves processing targeted machines manually and this isn’t the most effective way to do it.

As you might already know, under the Intune’s hood runs Microsoft Graph API which processes all actions which you do in GUI. Documentation from Microsoft which can be found on (https://docs.microsoft.com/en-us/graph/api/resources/intune-graph-overview?view=graph-rest-1.0) is good for the start in order to get better understanding on how this works and how to query the data. Additionally, real treasure is exposed to you by pressing the F12 key or using the combination Ctrl+Shift+I in your browser which will bring the Developer Tools panel.

At first, the amount of data presented can look quite confusing and you might be lost on where to start looking for something that might be useful. With using the Developer Tools option when sending the requests in GUI, you are presented with real requests which are happening in the back-end.

In this case, we are interested in being able to check the actual results of the script from GUI or Graph API side.

Simple Powershell script for testing

For the purpose of this post, I’m going to create a simple Powershell script which is creating the folder on user’s desktop:

# OBTAIN USERNAME OF THE LOGGED IN USER

$UserName = (Get-WmiObject -Class Win32_Process -Filter 'Name="explorer.exe"').GetOwner().User | Select-Object -First 1

# CREATE FOLDER IF IT DOESN'T EXISTS
$RequiredFolder = "C:\Users\$UserName\Desktop\Important Files"

$CheckRequiredFolder = Test-Path $RequiredFolder
if ($CheckRequiredFolder -eq $false)
{
  # CREATE REQUIRED FOLDER
  New-Item $RequiredFolder -ItemType Directory | Out-Null
}

For such simple tasks which are most likely not going to fail, you might think that this is enough, but what if the folder actually already exists on the machine? From the Intune GUI side, you would be presented with “Succeeded” result of the script anyway:

At that point, you wouldn’t know whether the folder was created since it didn’t exist, or it was already there.

In case you want to confirm the script status from the machine side, you can go to Registry in HKLM\SOFTWARE\Microsoft\IntuneManagementExtension\Policies\UserGUID\ScriptGUID. From that point of view, you are also seeing the script result showing as “Success” without additional details. Notice that there is an interesting key called ResultDetails which is currently empty:

You could expand the script to include logging of each step which was done during the script execution by using the Write-Output cmdlet:

# OBTAIN USERNAME OF THE LOGGED IN USER
$UserName = (Get-WmiObject -Class Win32_Process -Filter 'Name="explorer.exe"').GetOwner().User | Select-Object -First 1
Write-Output "$(Get-Date -Format 'dd-MM-yyyy_HH_mm_ss') - Username captured."

# CREATE FOLDER IF IT DOESN'T EXISTS
$RequiredFolder = "C:\Users\$UserName\Desktop\Important Files"

$CheckRequiredFolder = Test-Path $RequiredFolder

if ($CheckRequiredFolder -eq $false)
{
    Write-Output "$(Get-Date -Format 'dd-MM-yyyy_HH_mm_ss') - Folder not found, we will create one."
    New-Item $RequiredFolder -ItemType Directory | Out-Null
    Write-Output "$(Get-Date -Format 'dd-MM-yyyy_HH_mm_ss') - Folder $RequiredFolder created."
}
else
{
    Write-Output "$(Get-Date -Format 'dd-MM-yyyy_HH_mm_ss') - Folder already exists on the machine."
} 

You are again going to be presented with “Succeeded” result in the GUI, although we ran the script for the second time and until that point folder should have already been created.

Since we included the logging this time, we are hoping that this could been captured somewhere. When we return to the targeted machine again and check the Registry, we are seeing that ResultDetails key is being populated with results from our Write-Output commands:

However, this is not presented anywhere in the GUI and this is the point where you would advise the local IT support to provide you with details from that key, but what if you are interested in the result for couple of thousands of devices and want to be able to check the results yourself?

Using the Export button in Monitor -> Device status blade also exports just the current view to *.CSV file and currently there is no option to expand results with more columns.

Lets see what is hidden in the Graph API

This is where you start wondering is the content of ResultDetails key visible somewhere else. Since there is not much details in the Intune GUI, you end up digging into Microsoft Graph API.

If you start Developer Tools with F12 in your browser, you can see the requests which are being sent to Microsoft when you click through GUI. If I’m interested in seeing the request which is being sent when I click on Device status blade, I usually position myself anywhere else (for example User status blade) and then press F12. This brings the fresh empty Developer Tools pane and first request I place is going to be properly captured. When I click on Device status blade, I can see the requests popping up on the right side. Among them, I look for one of them which is having GET as Request Method (you’ll notice it easily by skipping those which are having Telemetry in their name). Above that information, there is a Request URL field which contains the data we need. Copy the data (in our case https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts/SCRIPTGUID/deviceRunStates?$expand=managedDevice) and have it ready in your clipboard:

Open the Graph API Explorer on https://developer.microsoft.com/en-us/graph/graph-explorer, authenticate with your administrative account, paste the URL in the necessary field and use the Run query button:

Depending on the amount of data which is queried, it can take some time for the results to appear (same as in GUI anyway). When query is finished, we are presented with results shown in JSON format and we can immediately see that more details are being shown here than in GUI.  

We can immediately notice that resultMessage property contains the log which we written during the execution of the script with Write-Output cmdlet:

That means that we can query the results now from Intune side and there is no need to wonder what exactly happened with the script or request logs from local IT support.

Same result is shown when we use Powershell to query the data (first you need to authenticate with Get-AuthToken function available on GitHub), for example:

$uri = "https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts/SCRIPTGUID/deviceRunStates?$expand=managedDevice"
$ScriptResult = (Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).Value
$ScriptResult

If we go back to the version of the script which didn’t had logging at all and query it’s results with Graph API, resultMessage property is indeed empty:

Since this property is being available from Graph API side, it would be helpful to have it from the GUI side as well, however this still remains “hidden” for some reason.

In this way, you can check results of your script and proactively react on it (for example, sending the local IT to the users whose machines had error with the script), as long as you implement correct logic and write your logs.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: