I’m excited to introduce a Serverless Local Administrator Password Solution (SLAPS 😉) for Windows 10 Intune Managed devices, powered by Microsoft Intune PowerShell scripts, Azure Functions and Azure Key Vault.

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 PowerShell script using the code below:

# Azure Function Uri (containing "azurewebsites.net") for storing Local Administrator secret in Azure Key Vault $uri = 'https://myfunctions.azurewebsites.net/api/SetKeyVaultSecret?code=myFunctionCode==' # Hide the $uri (containing "azurewebsites.net") from logs to prevent manipulation of Azure Key Vault $intuneManagementExtensionLogPath = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension.log" Set-Content -Path $intuneManagementExtensionLogPath -Value (Get-Content -Path $intuneManagementExtensionLogPath | Select-String -Pattern "azurewebsites.net" -NotMatch) 1 2 3 4 5 6 7 8 # Azure Function Uri (containing "azurewebsites.net") for storing Local Administrator secret in Azure Key Vault $uri = 'https://myfunctions.azurewebsites.net/api/SetKeyVaultSecret?code=myFunctionCode==' # Hide the $uri (containing "azurewebsites.net") from logs to prevent manipulation of Azure Key Vault $intuneManagementExtensionLogPath = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension.log" Set-Content -Path $intuneManagementExtensionLogPath -Value ( Get-Content -Path $intuneManagementExtensionLogPath | Select-String -Pattern "azurewebsites.net" -NotMatch )

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. Your Local Administrator credentials are safe, because they are never exposed, however your Key vault may get manipulated if the Azure Function is abused. If you require a better solution, please vote for Secure authentication within PowerShell scripts for Intune MDM on the Microsoft Intune UserVoice forums

Prerequisites

Before being able to configure the Local Administrator Password Solution using the instructions below, the following prerequisites must be met:

One or more Windows 10 Intune Managed device(s) must be in place and available;

Deploy an Azure Function App ;

; Deploy an Azure Key Vault ;

; Download the New-LocalAdmin.ps1 script from the TechNet Gallery;

script from the TechNet Gallery; Download the Set-KeyVaultSecret.ps1 script from the TechNet Gallery.

Note:

The Azure Function is using the experimental PowerShell language support. I’d be happy to share a C# example if anyone is up for the challenge 🙂

Configuration

Considering that a Function App and Key vault have already been deployed, I’ve divided the configuration of the Serverless Local Administrator Password Solution into six parts:

Register a Managed Service Identity with Azure Active Directory; Grant the Managed Service Identity access to the Key vault; Create the Azure Function; Test the Azure Function; Deploy the PowerShell script with Microsoft Intune; Validate the deployment of the PowerShell script;

1. Register a Managed Service Identity with Azure Active Directory

A Managed Service Identity needs to be registered with Azure Active Directory first, that will be used to authenticate with the Azure Key Vault.

Open the Azure Portal ;

; Navigate to Function Apps ;

; In the Functions Apps blade, select the Function App you wish to configure;

blade, select the you wish to configure; Navigate to the Platform features tab;

tab; Under Networking , click Managed service identity ;

, click ; Set Register with Azure Active Directory to On and click Save.

2. Grant the Managed Service Identity access to the Key vault

The next step is to add the Managed Service Identity to an Access policy in the Key vault.

Navigate to Key vaults ;

; On the Key vaults blade, select the Key vault you wish to configure;

blade, select the you wish to configure; In the Key vault blade that displays, click Access policies ;

blade that displays, click ; In the Access policies blade that displays, click Add new ;

blade that displays, click ; In the Add access policy blade that displays, click Select principal ;

blade that displays, click ; Enter the name of your Function App and click Select ;

and click ; In the Secret permissions , select Secret Management Operations > Set ;

, select > ; Click OK and click Save.

3. Create the Azure Function

Now that the Managed Service Identity of the Function App has been granted access to Set secrets in the Key vault. It’s time to create the Azure Function.

Navigate to Function Apps ;

; In the Functions Apps blade, select the Function App you wish to configure;

blade, select the you wish to configure; Select Functions and click New function ;

and click ; Enable the Experimental Language Support functions;

the functions; Click HTTP trigger > PowerShell ;

> ; Configure the new function: Language: PowerShell Name: Set-KeyVaultSecret Authorization level: Function

Replace the content of the Set-KeyVaultSecret function with the PowerShell code of the Set-KeyVaultSecret.ps1 file downloaded from the TechNet Gallery;

function with the code of the file downloaded from the TechNet Gallery; Set the name of your Key vault in the $keyVaultName variable;

of your in the variable; Click Save;

Note:

Take note of the Function URL (</> Get Function URL), which needs to be set in the New-LocalAdmin.ps1 script later. By default the Function App requires a TLS connection with a minimum version of 1.2.



4. Test the Azure Function

Before continuing to configure the PowerShell script in Intune that creates the Local Administrator accounts, it’s recommended to test if the Azure Function works as expected.

Grab the request body from the New-LocalAdmin.ps1 script;

script; Replace the variables with values, for example:

{ "keyName": "TEST-PC01", "contentType": "Local Administrator Credentials", "tags": { "Username": "localadmin" } } 1 2 3 4 5 6 7 { "keyName" : "TEST-PC01" , "contentType" : "Local Administrator Credentials" , "tags" : { "Username" : "localadmin" } }

Run the Azure Function and review the output;

If the Function runs successfully, a random password is returned the Output pane.

If the runs successfully, a random password is returned the pane. Validate the creation of the secret in the Key vault as defined in the keyName.



5. Deploy the PowerShell script with Microsoft Intune

Modify the configuration section of the New-LocalAdmin.ps1 script; Choose a username for the Local Administrator accounts; Enter the Function URL ;

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.

section of the script; In the Azure Portal, navigate to Intune > Device Configuration > PowerShell scripts ;

> > ; In the PowerShell scripts blade, click + Add ;

blade, click ; On the Add PowerShell script blade , enter the following information and click Create ; Name: New-LocalAdmin Script Location: Select the New-LocalAdmin.ps1 file, previously downloaded from the TechNet Gallery

, enter the following information and click ; In the New-LocalAdmin blade that displays, click Assignments ;

blade that displays, click ; Select a group you wish to deploy the solution to;

Save the assignments;

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 Management Extension. 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.

If you have any questions or feedback, feel free to leave a comment!