Serverless LAPS powered by Microsoft Intune, Azure Functions and Azure Key Vault!

Serverless LAPS powered by Microsoft Intune, Azure Functions and Azure Key Vault!

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:

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

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



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


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 ūüôā



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:

  1. Register a Managed Service Identity with Azure Active Directory;
  2. Grant the Managed Service Identity access to the Key vault;
  3. Create the Azure Function;
  4. Test the Azure Function;
  5. Deploy the PowerShell script with Microsoft Intune;
  6. 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;
  • Navigate to the Platform features tab;
  • Under¬†Networking, click¬†Managed service identity;
  • 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;
  • In the¬†Key vault¬†blade that displays, click¬†Access policies;
  • In the¬†Access policies blade that displays, click¬†Add new;
  • In the¬†Add access policy blade that displays, click¬†Select principal;
  • Enter the name of your¬†Function App and click¬†Select;
  • In the¬†Secret permissions, select¬†Secret Management Operations¬†>¬†Set;
  • 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;
  • Select¬†Functions and click¬†New function;
  • Enable the¬†Experimental Language Support 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;
  • Set the name of your Key vault in the $keyVaultName variable;
  • Click¬†Save;

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;
  • Replace the variables with values, for example:
  • Run the Azure Function and review the output;
    If the Function runs successfully, a random password is returned the Output 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.

  • In the Azure Portal, navigate to¬†Intune >¬†Device Configuration¬†>¬†PowerShell scripts;
  • In the¬†PowerShell scripts¬†blade, click¬†+ Add;
  • 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
  • In the¬†New-LocalAdmin¬†blade that displays, click Assignments;
  • Select a group you wish to deploy the solution to;
  • Save¬†the assignments;


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!


10 thoughts on “Serverless LAPS powered by Microsoft Intune, Azure Functions and Azure Key Vault!

  1. Pretty nice man… thanks for this! Have you made any changes since posting? Any better ways to control access to being able to invoke the Azure function, besides PKI?
    I went ahead and upvoted the uservoice on secure authentication through PowerShell.

    Thanks again!

  2. So I am failing on this somehow, interface changed and the “Managed Service Identity” has changed to “Identity” and the object seems to never exist when I create it. As such, when I run the script, I get this in out Output:

    “id”: “f7a61fa2-6aec-4672-b547-77154614306d”,
    “requestId”: “abeff90e-055f-4519-902d-6cfbcc64f389”,
    “statusCode”: 500,
    “errorCode”: 0,
    “message”: “An error has occurred. For more information, please check the logs for error ID f7a61fa2-6aec-4672-b547-77154614306d”

    and in the log window i receive:

    2019-03-19T16:37:16.952 [Info] Function started (Id=8459ee2d-f154-4355-aa5d-db8d0242faf8)
    2019-03-19T16:37:17.311 [Error] Invoke-RestMethod : {“error”:{“code”:”Forbidden”,”message”:”Access denied”,”innererror”:{“code”:”AccessDenied”}}}
    at run.ps1: line 34
    + Invoke-RestMethod
    + _________________
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
    2019-03-19T16:37:17.342 [Error] Exception while executing function: Functions.Set-KeyVaultSecret. Microsoft.Azure.WebJobs.Script: PowerShell script error. Microsoft.PowerShell.Commands.Utility: The remote server returned an error: (403) Forbidden.
    2019-03-19T16:37:17.373 [Error] Function completed (Failure, Id=8459ee2d-f154-4355-aa5d-db8d0242faf8, Duration=416ms)

    the permissions are set properly per this article so I am unsure why this is occurring.

    1. Hi Corey,

      You are getting an authentication error on setting the secret to Azure Key Vault. It seems that the Managed Service Identity (Service Principal) of the Function App itself does not have the “Secret permissions” set to “Set” on the Azure Key Vault, hence you get a 403 forbidden error.

      Can you double check that the “Access policy” on the Azure Key Vault, that it contains the “Application” (Function App) with “Secret permissions” set to “Set”? When I remove my Access Policy, I get the same error as you do.

Leave a Reply

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