Since a few months, it’s possible to upload PowerShell scripts to Intune as a part of you device configuration policies. These scripts will then be pushed to the linked Windows devies and run either under the SYSTEM account, or as the logged on user.
While working on an Intune deployment, I wanted to check the PowerShell scripts that are currently in use, and found out you can’t do that through the portal. You can change the properties of the script and upload a new file, but can’t view the current script.

Looking for a way to make the script visible, I started playing around with the Graph API, to see if we can do it via this route. Spoiler: we can! 🙂
Getting started with authenticating
First of all, we need to authenticate to the graph API. There is some great example code on the Microsoft Graph GitHub pages that explains how to do this, so I won’t go into any detail here. The scriptblock I use to authenticate result in a $authHeader hashtable, that we can include in our REST-calls to the Graph.
Setting up variables
First, I set a few variables in my script that I can re-use in my calls:
|
|
We need to use the beta version of the API, because the resources we need (deviceManagement/deviceManagementScrips) are not exposed in the currently stable version.
Calling the API
So, lets make our first call to the API to see what results we get back.
|
|
We set the URI we want to call, including the API version and resources specified earlier. Next, we call this URI using the invoke-restmethod cmdlet, including our authentication header we retrieved in the beginning. We use the ‘GET’ method, because we want to retrieve data. Because we set the resource to be deviceManagementScripts, the response will include the deviceManagementScripts currently in use.

Narrowing down the results
The response is a PSObject with several properties. Of course, we have the most interest in the ‘value’ property, as this has the actual data we are looking for. So, rewrite our line of code to get just the ‘value’.
|
|
This returns the actual deviceManagementScripts that are currently in use.
|
|
In my case, this is only one script that apparently is used to redirect certain folders to OneDrive.
Getting the content
By referencing the id for this script in our API call, we can get more information on this particular object.
|
|
Again, we use the GET
method to retrieve the information from the Graph API. Because we are referencing this single object, now we don’t need to distinctly retrieve the value
property to get the actual data.
|
|
For ease of reading in this output I truncated the scriptContent
property shown here a bit, but as you can see we can retrieve all the information we have in the portal: the description, the runAsAccount (that can be either ‘user’ or ‘system’), if a signature check is enforced, and of course the filename of the script and the actual content.
Making it readable
The content of the script is stored (and displayed) in a Base64-encoded string. To make this human readable, we need to decode it.
|
|
First, we specify the $script64
variable to store the Base64-encoding string. Next, we decode the Base64-string to UTF8 and store it in the $decodedscript
variable.
When we now display this $decodedscript
variable, we see the contents of the script!
|
|
Again, I truncated to output for readability here. Since we have this variable, we can store the contents in a file and thus save the script to our local harddrive.
|
|
Pretty neat, right? But, if we can use this to download a script, why shouldn’t we be able to upload a script this way? Let’s check. The documentation by Microsoft is pretty clear: we call the same deviceManagementSripts
resource, but with a POST
-method in stead of a GET
. In this POST
we need to include a JSON in the body with the details of the script we would like to set, including the actual content of the script in the same Base64-encoding we saw earlier.
Putting it together
So, let’s put the building blocks together. I’ve created a mind blowing Powershell-script that I stored as c:\temp\testscript.ps1
|
|
We get the content for this file and then encode it using Base64
|
|
So now we have the $UploadScriptEncoded
variable, containing the Base64-encoded script. Next, we need to build the JSON file to include in the POST
to the REST API. I do this by creating a hastable with all the needed information and piping this to the ConvertTo-JSON
cmdlet.
|
|
In the hashtable I specify the Displayname
for the script and a short description, include the scriptContent
we just encoded, specify it should run in the user-context and that we don’t want to check for a valid signature. Finaly, we give the filename for the script that will be displayed in the Intune portal where the script is referenced.
To finish up, we call the API with the given parameters to do the actual uploading.
|
|
We call the URI specified earlier, including our authentication header with the POST
-method. We include the JSON-file we stored in $postbody
as the body of the request, specifying that this is indeed a JSON-file.
The response indicates that file was uploaded and configured.
|
|
We can now check the Intune portal to double check if the script is there.

There you have it: using the Graph API you can do stuff you can’t do in the portal and automate many things you do Intune. For example, you can place the PowerShell scripts you deploy using Intune in a repository in (for example) VSTS and create a build sequence that uses the Graph API to update the script in Intune every time you push to master. If you haven’t played around with the Graph API, now is the time do so. The possibilities are endless.
Happy scripting!