Upload a PowerShell Script to Intune (With PowerShell) From Scratch

Published:22 May 2024 - 4 min. read

If you have Intune at your organization with some PowerShell scripts you need to run on remote machines, this tutorial is for you.

Let’s tackle a project where we'll cover everything from automating creating an Azure app registration, generating a client secret, obtaining a Microsoft Graph API token, and using that token to deploy a device management script. It might sound like a lot, but trust me, I'll guide you step-by-step!

Step 1: Install Required Modules and Authenticate to Azure

First things first, we need to install the required PowerShell modules and authenticate to Azure. This is a crucial step because without the right modules and proper authentication, nothing else will work. Open up your PowerShell console and run the following commands:

# Install necessary Azure PowerShell modules
Install-Module 'Az.Resources', 'Az.Accounts'

# Authenticate to Azure

When you run these commands, you'll be prompted to log into your Azure account. Follow the prompts, enter your credentials, and you'll be all set.

Step 2: Define Required Resource Access

Next, we need to define the resource access that our app registration will need. Specifically, we need to access the Microsoft Graph API with certain permissions. We'll define these permissions in a PowerShell hash table. This table includes the ResourceAppId, which is the ID for Microsoft Graph, and the ResourceAccess, which specifies the permissions our app will need. Here’s what that looks like:

# Define required resource access
$requiredResourceAccess = @(
        ResourceAppId  = "00000003-0000-0000-c000-000000000000"  # Microsoft Graph API ID
        ResourceAccess = @(
                Id   = "9241abd9-d0e6-425a-bd4f-47ba86e767a4"     # DeviceManagementConfiguration.ReadWrite.All permission ID
                Type = "Role"

Step 3: Create the App Registration

Now that we've defined the required resource access, let's create the app registration. This registration essentially tells Azure AD that we want to create a new application with the specified permissions. Run the following command:

$app = New-AzADApplication -DisplayName DeviceManagementScriptApp -RequiredResourceAccess $requiredResourceAccess

This command will register a new application in Azure AD with the specified permissions. The $app variable now holds the details of the newly created app.

Step 4: Generate a Client Secret

Next, we need to generate a client secret for our app registration. Think of this as a password for your app that allows it to authenticate and access resources securely. Here's how you do it:

$secret = New-AzADAppCredential -ObjectId $app.Id

This command creates a client secret, which we'll use later when making API calls. It's crucial to store this secret securely because it acts like a password for your app.

Step 5: Obtain a Microsoft Graph API Token

Now, we need to create a function to get a Microsoft Graph API token using our app's credentials. Tokens are essential for proving our identity when calling the API. The function below will help us obtain this token:

function getGraphApiToken {
    param (

    $body = @{
        grant_type    = "client_credentials"
        scope         = "https://graph.microsoft.com/.default"
        client_id     = $ClientId
        client_secret = $ClientSecret

    $tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" -Method Post -Body $body -ContentType "application/x-www-form-urlencoded"

# Example usage
$TenantId = "<Your-Tenant-ID>"
$ClientId = $app.ApplicationId
$ClientSecret = $secret.SecretText
$token = getGraphApiToken -TenantId $TenantId -ClientId $ClientId -ClientSecret $ClientSecret

This function sends a request to Azure AD's token endpoint to get an access token. The Invoke-RestMethod command is key here as it handles the HTTP POST request and returns the access token we need for further API calls.

Step 6: Prepare the Script Content

Let's move on to preparing the PowerShell script content we want to deploy. This script will be encoded in base64 format because the Graph API expects the script content in this format. Here’s how you do it:

# Define the script content
$someScriptContent = @'
## This is some PowerShell script
Test-Path C:

# Encode the script content to base64
$base64ScriptContent = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($someScriptContent))

We first define our script content, then convert it to a base64-encoded string, ensuring it’s properly formatted for transmission via the Graph API.

Step 7: Create the HTTP Body for the REST Call

Next, let's prepare the HTTP body for the REST call to the Graph API. This includes setting up the headers and body for our request. The headers will contain the authorization token, and the body will include details about the script, such as its content and language:

# Prepare the headers with the token
$headers = @{
    Authorization  = "Bearer $token"
    'Content-Type' = 'application/json'

# Create the HTTP body for the REST call
$body = @{
    "@odata.type"           = "#microsoft.graph.deviceManagementScript"
    "scriptContent"         = $base64ScriptContent
    "scriptLanguage"        = "PowerShell"
    "displayName"           = "Example Script"
    "description"           = "This is an example script."
    "runAsUser"             = "system"
    "runAs32Bit"            = $false
    "enforceSignatureCheck" = $false

Step 8: Make the API Call

Finally, let's set up the parameters for the REST API call and execute it. This step involves making a POST request to the Graph API endpoint to deploy our device management script.

powershellCopy code
# Set up the params for the REST API call
$irmParams = @{
    Uri                = 'https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts'
    Method             = 'POST'
    Headers            = $headers
    StatusCodeVariable = 'respStatus'
    SkipHttpErrorCheck = $true
    Body               = ($body | ConvertTo-Json)

# Make the API call
$response = Invoke-RestMethod @irmParams

# Handle any errors
if ($respStatus -ne 201) {
    throw $response.error.message
} else {
    Write-Output "Script deployed successfully!"

This code block sets up the parameters for the Invoke-RestMethod command, which sends our script content to the specified Graph API endpoint. The StatusCodeVariable captures the response status code to check if our request was successful. If everything goes well, you'll see "Script deployed successfully!" printed out.

And there you have it! You've successfully automated the process of creating an Azure app registration, generating a client secret, obtaining a Microsoft Graph API token, and deploying a device management script. This powerful workflow enables you to manage Azure resources efficiently and securely. Feel free to customize the script and parameters to suit your specific needs. Happy scripting!

Hate ads? Want to support the writer? Get many of our tutorials packaged as an ATA Guidebook.

Explore ATA Guidebooks

Looks like you're offline!