Workspace ONE UEM – PowerShell Profile

We can do a lot of things in Workspace ONE UEM especially when it comes to custom profile. We can do custom profile for OMA-DM client but we can do it Intelligent Hub too. An interesting profile for the Intelligent Hub is the PowerShell one, little known but very useful. This profile allow to run PowerShell commands from Intelligent Hub.

Sensors Vs Profile

You could argue that with Sensor within the console you can do the same. While this is true, you have to remember that Sensor is for taking the “pulse” of the device and returning information back so it can bring more data so more insight.
The profile on the other hand is there to do configuration of the device.

32 Bits Vs 64 Bits

Intelligent Hub currently run as a 32 bit process. So any command run from there would access to the 32 bit side, like registry and System32 folder.

To run something in 64 Bits, you need to use sysnative which will target the right folder or registry access.

Sending PowerShell commands

To send PowerShell commands, you need to use the following profile.

<wap-provisioningdoc id="INSERT-GUID" name="customprofile">
  <characteristic type="com.airwatch.winrt.powershellcommand" uuid="INSERT-GUID">
    <parm name="PowershellCommand" value=""/>
  </characteristic>
</wap-provisioningdoc>

Insert the command in the value string and insert new GUID for id and uuid.

You can use the following command to generate new GUID

[GUID]::NewGuid().ToString()

Example:

<wap-provisioningdoc id="b0774572-29ec-4015-8bde-8f0281682f1b" name="customprofile">
  <characteristic type="com.airwatch.winrt.powershellcommand" uuid="f060bc02-bc0d-4ff8-b5d7-3fdfd24274dd">
    <parm name="PowershellCommand" value="Invoke-Command -ScriptBlock {C:\windows\ccmsetup\ccmsetup.exe /uninstall}"/>
  </characteristic>
</wap-provisioningdoc>

As you can see we can do anything PowerShell related, but how about scripts.

Sending PowerShell script

You can inject script in the value but it can be tricky due to XML parsing so there is escape to be done and it can result in not having the script to run properly. PowerShell offer another way to execute a script without a .ps1 file, which is -EncodedCommand switch. It uses Base64 encoding to avoid issue with special characters.

To encode a PowerShell command to Base64 you need to do the following:

  • Get the bytes of the command in UTF16-Little Endian
  • Convert the bytes to Base 64

This is described in the PowerShell help

# To use the -EncodedCommand parameter:
$command = 'dir "c:\program files" '
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -encodedCommand $encodedCommand

You can do this for little command as described above but you can as well do it for longer script like so:

#EncodedCommand for a script
$Script = Get-content -Path .\MyScript.ps1 -Raw
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -encodedCommand $encodedCommand

Note the -raw for the Get-Content command. This is very important because it will get the content as a unique string with all the line return. Without it, Get-Content treat each line as unique and import the file as an array of lines then the conversion to Base64 will lead to a one liner without the line return which is not the intention. If we take the example above, the Base64 conversion without -raw will lead to this:

#EncodedCommand for a script $Script = Get-content -Path .\MyScript.ps1 -Raw  $bytes = [System.Text.Encoding]::Unicode.GetBytes($command)  $encodedCommand = [Convert]::ToBase64String($bytes)  powershell.exe -encodedCommand $encodedCommand

The first line is a comment so the end result is one big comment instead of our script…

Building Profile Easily

While this fairly easy to do it in the PowerShell console, copying and pasting the Base64 value in the profile can lead to error and also while trying to run PowerShell in 64 Bits it add more complexity to the whole XML as you need to run the following command

&$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe

But the & need to be escaped to &amp; due to XML parsing.

So I’ve created a PowerShell script to generate profile and save it as a XML file depending on the architecture targeted.

Usage:

.\Create-PowerShellProfile.ps1
        -FilePath .\MyScript.ps1
        -Arch 32 or 64

https://github.com/CamilleDebay/Scripts/blob/master/UEM/Create-PowerShellProfile.ps1

Limitations

There is a Windows limitation on the maximum length of a command line which is 32767 characters long. I’ve implemented this check in the script, it will give an error and won’t generate the profile if the command line is longer than this maximum.

Create profile in UEM

Once you have the XML you need to create a profile to deploy it.

In the Windows Desktop section, select either User or Device profile then Custom Settings.

Select Workspace ONE Intelligent Hub as the Target, un-tick “Make Commands Atomic” and paste the XML content in the Install Settings.

The Remove Settings section is mandatory so you can put another XML script which would undo what is done in the Install section.

Troubleshooting

The PowerShell command are handled by AWProcessCommands which create a log file named AWProcessCommands.log in %ProgramData%\Airwatch\UnifiedAgent\Logs folder.