Pass Parameters to a PowerShell Script Packaged as an .intunewin Win32 App
|

Pass Parameters to a PowerShell Script Packaged as an .intunewin Win32 App

Reading Time: 7 minutes

Learn how to pass parameters to a PowerShell script inside an .intunewin package deployed via Intune Win32 app management – with real examples and gotchas.

A common question from Intune admins who package PowerShell scripts as Win32 apps is whether you can pass parameters at deploy time rather than hardcoding them inside the script. The answer is yes! This post covers exactly how to do it, with real-world use cases, working patterns, and the gotchas that will catch you if you’re not careful.



Why Package a PowerShell Script as a Win32 App?

Intune has a native Platform Scripts feature for running PowerShell on devices. So why go through the effort of packaging a script as a Win32 app?

A few common reasons:

  • Detection rules – Win32 apps support file, registry, and custom script detection. You can make Intune track whether the script has already run successfully and skip it on subsequent syncs.
  • Dependencies – Win32 apps support dependency chains. You can ensure prerequisites are installed before your script fires.
  • Bundled files – Your script may need additional files alongside it (config files, binaries, certificates). You can package everything into a single .intunewin.
  • Return code control – Win32 apps give you full control over how exit codes are interpreted (success, soft reboot, hard reboot, retry).

None of these are available with the Platform Scripts feature. And once you go down the Win32 path, you’ll immediately run into the question: how do I get values into the script without rebuilding the package every time something changes?

That’s where the Install command field comes in.


How Parameters Actually Get Passed

When you configure a Win32 app in Intune, the Install command field is a free-text command line. This is not just a path to your installer – it is the full command that the Intune Management Extension (IME) will execute on the device, inside the extracted package folder.

That means you write it exactly like you would in a terminal:

powershell.exe -ExecutionPolicy Bypass -File .\YourScript.ps1 -ParameterName "Value"

Intune extracts the .intunewin contents to a temp folder and runs this command from within it. Your .ps1 file just needs to be inside the package – everything after -File .\YourScript.ps1 is passed directly to the script as arguments.

Note: The IME runs Win32 apps in the SYSTEM context by default (unless you switch to User context). Any parameters you pass via the Install command are baked into the app configuration at the Intune portal level – they are not dynamic per-user or per-device at runtime.


Real-World Use Cases

A few scenarios where this pattern is genuinely useful:

  • Environment-based configuration – You have one script that installs a configuration agent. You create two Win32 apps – one for Production and one for Staging – using the same .intunewin but passing a different -Environment parameter in each app’s Install command. No duplicate scripts.
  • Registry value injection – A script that writes a registry key. The key path is the same, but the value differs between device groups. Pass the value as a parameter instead of duplicating the script.
  • Log path or output target – Your script writes logs or output somewhere. Pass -LogPath as a parameter so you can control the destination from Intune without touching the script.
  • Feature flags – A deployment script that supports a -Mode parameter (e.g., Install, Configure, Repair). You package once and create multiple Win32 apps for each mode.

Pass Parameters Pattern 1 – Simple Named Parameters

This is the most common pattern. Your script has a param() block at the top, and you pass values via the Install command.

The script (inside the .intunewin):

# Configure-Agent.ps1
param(
    [string]$Environment = "Production",  # Default value if not passed
    [string]$LogPath = "C:\ProgramData\Logs"
)

# Create log directory if it doesn't exist
New-Item -ItemType Directory -Path $LogPath -Force | Out-Null

# Write to log
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"[$timestamp] Running configuration for environment: $Environment" | Out-File "$LogPath\configure.log" -Append

# Your logic here
if ($Environment -eq "Staging") {
    # Apply staging-specific configuration
    Write-Host "Applying Staging configuration..."
} else {
    # Apply production configuration
    Write-Host "Applying Production configuration..."
}

exit 0  # Always return an explicit exit code for Intune

The Install command in Intune (for the Staging app):

powershell.exe -ExecutionPolicy Bypass -File .\Configure-Agent.ps1 -Environment "Staging" -LogPath "C:\ProgramData\MyApp\Logs"

The Install command in Intune (for the Production app – same .intunewin):

powershell.exe -ExecutionPolicy Bypass -File .\Configure-Agent.ps1 -Environment "Production" -LogPath "C:\ProgramData\MyApp\Logs"

You package the script once with IntuneWinAppUtil, upload it once, and create two separate Win32 apps pointing at the same .intunewin – each with a different install command. No duplicate scripts, no rebuild.

create app in intune with parameters
deployed app with packaged powershell script with parameters

Pass Parameters Pattern 2 – Multiple Parameters with a Config Flag

A slightly more advanced pattern: a script that supports a -Mode switch, letting you reuse one package across install, configure, and repair scenarios.

The script:

# Manage-Software.ps1
param(
    [ValidateSet("Install","Configure","Repair")]
    [string]$Mode = "Install",

    [string]$Version = "1.0.0"
)

switch ($Mode) {
    "Install" {
        Write-Host "Installing version $Version..."
        # Run installer logic
        exit 0
    }
    "Configure" {
        Write-Host "Applying configuration for version $Version..."
        # Apply post-install settings
        exit 0
    }
    "Repair" {
        Write-Host "Running repair for version $Version..."
        # Repair logic
        exit 0
    }
}

Install command – Install mode:

powershell.exe -ExecutionPolicy Bypass -File .\Manage-Software.ps1 -Mode "Install" -Version "2.1.0"

Install command – Repair mode (a separate Win32 app, same .intunewin):

powershell.exe -ExecutionPolicy Bypass -File .\Manage-Software.ps1 -Mode "Repair" -Version "2.1.0"

The detection rule differentiates whether each “app” has run successfully, so Intune knows which mode has been applied.


The New PowerShell Script Installer Type – and Why Parameters Don’t Work There

Microsoft recently introduced a new installer type for Win32 apps: instead of calling powershell.exe from the Install command, you can upload a .ps1 directly in the Intune portal as the installer. The script becomes part of the app configuration – editable without repackaging. Small script fixes no longer mean a full .intunewin rebuild and re-upload. You just edit the script in the portal and sync.

However – this approach does not support parameters.

When you use the PowerShell Script installer type, Intune runs the script as-is. There is no Install command field to append arguments to. Any values your script needs must be hardcoded inside it, or read from somewhere the device can reach (a file, a registry key, an environment variable written by a previous step).

Classic Install CommandPowerShell Script Installer
Parameters supportedYes – via Install commandNo
Script editable without repackageNoYes
Bundled files supportedYesYes (payload still needed)
Detection rulesYesYes
Best forParameterised, reusable deploymentsRapid changes on simple installs

If you need parameters – stick with the classic powershell.exe -File approach in the Install command. If you want easy script editing and don’t need parameters, the new installer type is worth using.


Gotchas

32-bit PowerShell

This is the most common silent failure. The Install command in Intune launches a 32-bit PowerShell process by default. If your script uses 64-bit-only APIs, registry hives (e.g., HKLM:\SOFTWARE without redirection), or modules that only exist in 64-bit, it will fail silently or behave incorrectly.

Force 64-bit explicitly:

%SystemRoot%\Sysnative\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File .\YourScript.ps1 -Param "Value"

Sysnative is a special alias available in 32-bit processes on 64-bit Windows that redirects to the real 64-bit System32 folder.


Quoting and Spaces in Parameter Values

If a parameter value contains spaces, it must be quoted. But quoting inside the Intune Install command field can get tricky because the field is itself a string. Use escaped double quotes or single quotes carefully.

Works:

powershell.exe -ExecutionPolicy Bypass -File .\Script.ps1 -Path "C:\Program Files\MyApp"

Breaks (no quotes around the path):

powershell.exe -ExecutionPolicy Bypass -File .\Script.ps1 -Path C:\Program Files\MyApp

If you hit edge cases with nested quoting, a wrapper approach helps – write a cmd.exe launch that handles the quoting, or embed the value directly in a second small wrapper script inside the same .intunewin.


Array Parameters Don’t Pass Cleanly

If your script expects an array parameter like [string[]]$Paths = @(), passing an array literal through the Install command line (e.g., @(‘C:\Folder1′,’C:\Folder2’)) will not work correctly in most cases. PowerShell’s argument parsing strips or misinterprets the array syntax when called via -File.

The cleaner workaround: pass a delimited string and split it inside the script.

Install command:

powershell.exe -ExecutionPolicy Bypass -File .\Script.ps1 -Paths "C:\Folder1;C:\Folder2;C:\Folder3"

Script:

param(
    [string]$Paths = ""
)

# Split the delimited string into an array
$pathArray = $Paths -split ";"

foreach ($path in $pathArray) {
    Write-Host "Processing: $path"
}

Parameters Are Visible in IME Logs

Whatever you put in the Install command is logged by the IME. If a parameter value is sensitive (a password, a token, a licence key), passing it this way is a bad idea. Consider reading sensitive values from a secure source the script can reach at runtime – such as a value written by a previous step, a certificate, or a managed identity call.


Troubleshooting – IME Logs

When a Win32 app fails to install or behaves unexpectedly, the first place to look is the IME log folder on the device:

C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\

The most relevant files:

  • IntuneManagementExtension.log – Main IME log. Shows app download, extraction, and command execution.
  • AppWorkload.log – Shows the install command that was actually executed, the working directory, exit code, and whether detection succeeded.

In AppWorkload.log you can confirm:

  • The exact command line that was run (including your parameters)
  • The temp extraction folder path
  • The exit code returned by your script
  • Whether detection passed or failed after install

If the Install command looks right in the portal but the wrong (or no) parameters appear in the log, check the 32-bit/64-bit issue first – a 32-bit PowerShell process that immediately exits due to a missing module or policy error can silently drop your parameters before they’re parsed.


References and Documentation

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *