SOLVED

Resetting User’s Password using Microsoft Graph API

Iron Contributor

Working on a project to develop a tool and one aspect this tool is to rest a user’s password using Graph API with Application Permissions. Been searching on the internet and found a lot of suggestions on using delegate and application permissions; however, I was unable to get the password reset to work using Graph API.

 

Environment Information: we have an on premise active directory and user azure ad connect to sync account to Azure AD with Password write back.

 

Question: How can I reset a user’s password in Azure AD using only Microsoft Graph API with Application permissions? What permissions I’ll needed use for the application and URI I would need to use.

 

The last option I tried can be found on this website: https://levelup.gitconnected.com/how-to-reset-or-update-user-passwords-with-microsoft-graph-api-in-a...

From this website I tried “The solution to use AAD PowerShell V2.0”

 

Thank You,

Larry

15 Replies
best response confirmed by Larry Jones (Iron Contributor)
Solution
Afaik application permissions are not supported for this operation.
Thank You for responding
@Vasil Michev

I working off the following Microsoft Document to reset a users password using graph.

https://docs.microsoft.com/en-us/graph/api/passwordauthenticationmethod-resetpassword?view=graph-res...

I created a service account:
- gave that account "Authentication admin" privileged
- add UserAuthenticationMethod.ReadWrite.All permission to app in APP Registration

Question: Do you have any recommendation on what I would need to get graph for PW reset to work?

Also, I have additional question, I'm still new to whole using Microsoft Graph API within my PowerShell. How can I make the payload (password) a $variable?

Thank You,
-Larry

Below is the snapshot of the script I'm trying to get to work
###############################################

Function HeaderToken-RW
{
# Define AppId, secret and scope, your tenant name and endpoint URL
$AppId = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
$AppSecret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
$Scope = "https://graph.microsoft.com/.default"
$TenantName = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

# Add System.Web for urlencode
Add-Type -AssemblyName System.Web

# Create body
$Body = @{
client_id = $AppId
client_secret = $AppSecret
scope = $Scope
grant_type = 'client_credentials'
}

# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'
# Create string by joining bodylist with '&'
Body = $Body
Uri = $Url
}

# Request the token!
$Request = Invoke-RestMethod @PostSplat

# Create header
$Header = @{Authorization = "$($Request.token_type) $($Request.access_token)"}

Return $Header
}#End Header Function

$AdminName = 'xxxxx@xxxx.com'
$EncryptPW = "xxxxxxxxxxxxxxxx"
$UserCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AdminName, ($EncryptPW | ConvertTo-SecureString)


$UserAZGUID = 'XXXXXXXXXX-XXXXXXXXX-XX-XXXXXXXXXX-XXXX'
$HeaderRW = HeaderToken-RW
$PWResetURI = "https://graph.microsoft.com/beta/users/$UserAZGUID/authentication/passwordMethods/$UserAZGUID/resetP..."
$Body = '{"newPassword" : "password"}'

$UserResult = Invoke-RestMethod -Headers HeaderRW -Uri $PWResetURI -Method POST -Body $Body -Credential $UserCredential -ContentType "application/json"


Something like this should do:

$password = "password"
$Body = '{"newPassword" : $password}'

or you can just ask for input via Read-Host or similar. Or not specify a password at all, in which case a random one would be generated.

@Vasil Michev 

 

Thank You for responding, and sorry for not responding sooner apparently there was an issue with my RSS feed in Teams.

 

Can't use Read-Host, this function being build into a service desk application.

 

When I execute PW reset Function I receive the following error:


[Line 304] Password randomly generated by script kaHF539*@
Invoke-RestMethod : The remote server returned an error: (401) Unauthorized.
At line:76 char:15
+ ... serResult = Invoke-RestMethod -Uri $PWResetURI -Method POST -Body $Bo ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

###################################

Permission applied to the API

 

####################################

Function HeaderToken-RW
{

## extract of header token function - see the full Header Token function within this thread  ##
# Define AppId, secret and scope, your tenant name and endpoint URL
$AppId = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
$AppSecret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
$Scope = "https://graph.microsoft.com/.default"
$TenantName = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

 

Return $Header
}#End Header Function

## end of extract of header token function ##

 


function Get-RandomCharacters($length, $characters)
{
$random = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length }
$private:ofs=""
return [String]$characters[$random]
}

$password = Get-RandomCharacters -length 2 -characters 'abcdefghiklmnoprstuvwxyz'
$password += Get-RandomCharacters -length 2 -characters 'ABCDEFGHKLMNOPRSTUVWXYZ'
$password += Get-RandomCharacters -length 3 -characters '1234567890'
$password += Get-RandomCharacters -length 2 -characters '!@$&%*'
Write-Host "[Line 304] Password randomly generated by script "$password -ForegroundColor Yellow

 

####################################


$AdminName = 'XXXXXXXXXX.com'
$EncryptPW = "XXXXXXXXXXXXXXXX"
$UserCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AdminName, ($EncryptPW | ConvertTo-SecureString -Key $Key)

 

 

$UserAZGUID = 'XXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'

$PWResetURI = "https://graph.microsoft.com/beta/users/$UserAZGUID/authentication/passwordMethods/$UserAZGUID/resetp..."

 

$Body = '{"newPassword" : "$password"}'

$HeaderRW = HeaderToken-RW


$UserResult = Invoke-RestMethod -Headers HeaderRW -Uri $PWResetURI -Method POST -Body $Body -Credential $UserCredential -ContentType "application/json"

 

 

-Thank You

 

 

I dont see a request for actually getting the token, did you just omit it in the copy paste or in the actual script? :)

@Vasil Michev  Again Thank You.....

 

Here's the function I use to get the Token. 

 

Function HeaderToken-RW
{
# Define AppId, secret and scope, your tenant name and endpoint URL
$AppId = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
$AppSecret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
$Scope = "https://graph.microsoft.com/.default"
$TenantName = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

# Add System.Web for urlencode
Add-Type -AssemblyName System.Web

# Create body
$Body = @{
client_id = $AppId
client_secret = $AppSecret
scope = $Scope
grant_type = 'client_credentials'
}

# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'
# Create string by joining bodylist with '&'
Body = $Body
Uri = $Url
}

# Request the token!
$Request = Invoke-RestMethod @PostSplat

# Create header
$Header = @{Authorization = "$($Request.token_type) $($Request.access_token)"}

Return $Header
}#End Header Function

 

 

Thank You,

-Larry

So you're still using application permissions (client secret), they are not supported for this endpoint.

@Vasil Michev 

Again Thank you for responding!!!


Yes that is correct, using the application token did not work. Since I wasn't having any luck getting this API call to work i tried using -Header or -credential or both options.

 

At the bottom of this messages is the function I tried using just credentials and this too failed with the following error.

 

 Invoke-RestMethod : The remote server returned an error: (401) Unauthorized.
At line:30 char:15
+ ... serResult = Invoke-RestMethod -Uri $PWResetURI -Method POST -Body $Bo ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExcep

 

Do you have a recommendation on how I can get this to work?

 

Thank You,

-Larry

 

$Key = 'XXXXXXXXXXXXXX'
$AdminName = 'XXXXXXXXXX.com'
$EncryptPW = "XXXXXXXXXXXXXXXX"
$UserCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AdminName, ($EncryptPW | ConvertTo-SecureString -Key $Key)

$UserAZGUID = 'XXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
$PWResetURI = "https://graph.microsoft.com/beta/users/$UserAZGUID/authentication/passwordMethods/$UserAZGUID/resetp..."


function Get-RandomCharacters($length, $characters)
{
$random = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length }
$private:ofs=""
return [String]$characters[$random]
}

 

$password = Get-RandomCharacters -length 2 -characters 'abcdefghiklmnoprstuvwxyz'
$password += Get-RandomCharacters -length 2 -characters 'ABCDEFGHKLMNOPRSTUVWXYZ'
$password += Get-RandomCharacters -length 3 -characters '1234567890'
$password += Get-RandomCharacters -length 2 -characters '!@&%(*'
Write-Host "[Line 304] Password randomly generated by script "$password -ForegroundColor Yellow

 

$EncryptUserPW = ConvertTo-SecureString -String $Password -AsPlainText -Force

 

$Body = '{"newPassword" : "$EncryptUserPW"}'
$UserResult = Invoke-RestMethod -Uri $PWResetURI -Method POST -Body $Body -Credential $UserCredential -ContentType "application/json"

 

You need to pass the token as part of the header. Also, you seem to be passing the user's GUID instead of the actual authentication method id. Here's a working example:

$body = @{
"newPassword" = "Parola123"
}

$uri = "https://graph.microsoft.com/beta/users/user@domain.com/authentication/passwordMethods/28c10230-6103-..."
Invoke-WebRequest -Headers $authHeader -Uri $uri -Method Post -ErrorAction Stop -Body ($body | ConvertTo-Json -Depth 6)
Again thank You and I'm sorry for not grasping the concept, I still must be missing something.

Here is my script from start to finish.

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

Function HeaderToken
{
# Define AppId, secret and scope, your tenant name and endpoint URL
$AppId = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
$AppSecret = 'xxxx.xxx.x..xxxx.x!!!!!111xxxxxx'
$Scope = "https://graph.microsoft.com/.default"
$TenantName = "XXXXXXXXXXXXXXXXXX.com"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"
# Add System.Web for urlencode
Add-Type -AssemblyName System.Web
# Create body
$Body = @{
client_id = $AppId
client_secret = $AppSecret
scope = $Scope
grant_type = 'client_credentials'}

$PostSplat = @{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'
# Create string by joining bodylist with '&'
Body = $Body
Uri = $Url}

# Request the token!
$Request = Invoke-RestMethod @PostSplat

# Create header
$Header = @{Authorization = "$($Request.token_type) $($Request.access_token)"}

Return $Header
}#End Header Function


$authHeader = HeaderToken
$Body= @{
"newPassword" = "dkrRBW122"
}

$uri = "https://graph.microsoft.com/beta/users/xxxxx@xxxxxxxxx.com/authentication/passwordMethods/xxxxxxxx-x..."
Invoke-WebRequest -Headers $authHeader -Uri $uri -Method Post -ErrorAction Stop -Body ($body | ConvertTo-Json -Depth 6)


#################### Error ###################
Getting the same error:
Invoke-WebRequest : The remote server returned an error: (403) Forbidden.
At C:\Users\jonesl\Desktop\Powershell Scripts\_BabylonProject\API-PWRest-Not Working.ps1:61 char:1
+ Invoke-WebRequest -Headers $Header -Uri $uri -Method Post -ErrorActio ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand


Thank You,

-Larry
That sample is still using application permissions/client secret, it will not work. Update your HeaderToken function.
Thank you Again and I believe that's the issue. After re-reading the Microsoft document that deals with passwordAuthenticationMethod: resetPassword, the authentication method is a Bearer {token}.

After reading through several site on how to construct a Bearer token using PowerShell, I'm still

Can you provide an basic example or point me to a good website that offer step by step instruction that will allow me to create Bearer Token using Credentials using PowerShell.

Thank You very much for the time your spending with me to get this to work.


-Larry

Here's a simple example that uses a username/password. Best work through the documentation and find the method that best works for you.

$req = Invoke-WebRequest -Method Post -Uri "https://login.microsoftonline.com/tenantname.onmicrosoft.com/oauth2/token" -Body "client_id=xxxxxxxxx-xxxx-xxxx-xxxx-da3ab8e46b00&grant_type=password&username=user@domain.com&password=P@ssw0rd123&scope=openid&resource=https://graph.microsoft.com" -Headers @{"Content-Type"="application/x-www-form-urlencoded"}
$token = ($req.Content | ConvertFrom-Json).access_token
Thank You very much - had to make some adjustments but at least I'm getting the token and it's working. I tested on another endpoint because I was getting "Invoke-RestMethod : The remote server returned an error: (405) Method Not Allowed." on the password rest (passwordAuthenticationMethod) endpoint .


Now that I'm able to make it work, I'm able to take what you show me and expand on making more efficient.

Than You Very Much!!!!!!!

-Larry
1 best response

Accepted Solutions
best response confirmed by Larry Jones (Iron Contributor)
Solution
Afaik application permissions are not supported for this operation.

View solution in original post