Building this solution has been quite a challenge, as there were many obstacles to overcome. If you’ve read the article of Oliver Kieselbach: “Deep dive Microsoft Intune Management Extension – PowerShell Scripts“, then you know that all script contents are logged in plain text (including passwords!) to the IntuneManagementExtension.log file. So I had to come up with a solution that would not expose passwords in plain text at any time.

That’s where Azure Functions come in! I managed to create an HTTP-based API, using the experimental PowerShell language support in a Function App, that contains all of the logics for returning random passwords on demand and simultaneously storing them securely into an Azure Key Vault. Passwords are contained in a variable and never exposed in plain text.

From the Intune PowerShell script, the Azure Function is queried over a TLS 1.2 encrypted connection, using the Invoke-RestMethod cmdlet. The hostname of the initiating device, and the username defined in the PowerShell Script are used to create the Local Administrator, and are also passed with the POST method to the Azure Function within the request body of the Invoke-RestMethod cmdlet.

When the Azure Function is triggered, it will return a random generated password to the PowerShell script, and also creates or updates a secret in your Azure Key Vault. The name of the secret is based on the hostname of the device. The value will be the randomly generated password, and the username is added as a tag.

Sounds nice, right? But there’s one more challenge… I don’t want to expose the url containing the authorization code to trigger the Azure Function in plain text within the log file. I want to be able to rely on the contents of Key vault. Exposing this information would allow anyone to read the log file and put false information in the Key vault, by executing the same cmdlets with modified data. I figured out I could manipulate the log file during the runtime of the PowerShellscript using the code below:

This would remove each line from the log file that matches the “azurewebsites.net” string.

Note:Please note that this is just a workaround to hide information from the log file. It is absolutely not waterproof. An ‘attacker’ will still be able to retrieve the contents of the PowerShell script. The Intune Management Extension will download scripts just before they are executed to “C:\Program Files (x86)\Microsoft Intune Management Extension\Policies\Scripts”, where it will be removed after execution.

5. Deploy the PowerShell script with Microsoft Intune

The New-LocalAdmin.ps1 script will restart itself in a 64-bit process, because cmdlets like New-LocalUser are not available in a 32-bit process, which is the architecture of the Intune Management Extension agent.

Note:
PowerShell scripts can only be deployed to users. On shared devices, the provided PowerShell script will change the password of the Local Administrator user every time a new user logs on to a device.

6. Validate the deployment of the PowerShell script

PowerShell scripts are executed by the Intune ManagementExtension. The agent will check every 60 minutes if a script is ready to be deployed. You can force a sync by restarting the Microsoft Intune Management Extension Service on the device.

The status of the PowerShell script deployment is returned to the Monitor > Device/User status overview in Intune.

When the PowerShell script succeeds, validate the creation of a Local Administrator on the device, and that the credentials were stored in the Key vault.

More information

Need to troubleshoot further? Check the log files on a device at C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension.log, which contains the logging for PowerShell Scripts.