Update AzureAD/O365 UPN via Graph - powershell

I am attempting to update the UPN of an Azure AD user (loaded with Azure AD Connect) in a federated domain via MS Graph leveraging the .Net ADAL library in Powershell. I am reasonably certain that I have everything configured correctly within Azure and in the PS, because if I issue a command to update the usageLocation attribute, it works (clipped for brevity):
$UPN="user#mytenant.edu"
$Body=#{UsageLocation="JP"} | ConvertTo-JSON
$Result=Invoke-RestMethod -Method PATCH -Uri "https://graph.microsoft.com/v1.0/users/${UPN}" -Headers #{Authorization=$authenticationResult.CreateAuthorizationHeader()} -ContentType "application/json" -Body $Body
$user=Invoke-RestMethod -Method GET -Uri "https://graph.microsoft.com/v1.0/users/${UPN}?`$select=usageLocation" -Headers #{Authorization=$authenticationResult.CreateAuthorizationHeader()} -ContentType "application/json"
$user.usageLocation
JP
But, if I attempt to update the UPN to a non-federated domain (so I do not run afoul of the issue described in http://blogs.perficient.com/microsoft/2013/03/changing-upn-for-office-365-account-between-two-sso-domains/), I get back an Internal Server Error (500):
$UPN="user#mytenant.edu"
$Body=#{userPrincipalName="user#tenant.onmicrosoft.com"} | ConvertTo-JSON
$Result=Invoke-RestMethod -Method PATCH -Uri "https://graph.microsoft.com/v1.0/users/${UPN}" -Headers #{Authorization=$authenticationResult.CreateAuthorizationHeader()} -ContentType "application/json" -Body $Body
Invoke-RestMethod : The remote server returned an error: (500) Internal Server Error.
I've tried many different variations, including retrieving the Azure AD GUID and using that rather than UPN in the PATCH command and using the older Azure AD Graph (which returns the same 500 error). I can make the change using O365 Powershell commands:
Set-MsolUserPrincipalName -UserPrincipalName $UPN -NewUserPrincipalName $newUPN
but I can't seem to make it work via MS Graph. The docs for graph imply that UPN can be updated like other attributes (c.v. http://graph.microsoft.io/en-us/docs/api-reference/v1.0/api/user_update, for example). I'm wondering though if because UPN is a key, maybe that makes update not work? I also don't think this is a permission issue, those usually throw "Insufficient privileges to complete the operation." which is not what I'm seeing.
Thank you!
UPDATE1: Here's everything I can fish out of the Error object from a re-attempt this morning :
{
"error": {
"code": "Service_InternalServerError",
"message": "Encountered an internal server error.",
"innerError": {
"request-id": "cbb08d3c-1143-4d0b-8722-5230b00bd00f",
"date": "2016-02-15T16:48:15"
}
}
}

I took a look at the trace, and I will file a bug on our side for the 500 error (we can certainly do better here). Based on the trace, if you are updating a user by renaming them out of a federated domain into a cloud managed domain, you MUST provide/set a password as part of the request (using passwordProfile complex type). That is why the request is failing according to the logs. Please let us know if this solves your issue.

Related

How do I log on to JIRA in PowerShell using REST when basic authentication in plain text is blocked?

I've been trying to access our on-prem JIRA Server (configured with plain HTTP) using PowerShell Invoke-RestMethod, but I think I'm missing something.
The authentication header is created in base64
$cred = [convert]:.ToBase64String([text.encoding]::ASCII.GetBytes("account:password"))
$headers = #{Authorization = "Basic $cred"}
Using REST, I then ask for the issue (without posting any property filter to keep the request simple while I'm learning).
Invoke-RestMethod -Uri http://jiraserver:8080/jira-software/REST/agile/1.0/issue/test-1 `
-Headers $headers -ContentType "application/json" -AllowUnencryptedAuthentication
This obviously fails, as I get back a reply containing a login form
<form action="/login.jsp"
class="aui"
id="login-form"
method="post">
I do think I remember that basic authentication is no longer supported in JIRA.
How do I use OAuth in that case instead?
When working with another task that is well within the scope of AtlassianĀ“s PowerShell module JiraPS, I noticed a command called Invoke-JiraMethod.
It turns out that the module provides JIRA REST API access :)
So by setting up a JIRA session with the PowerShell module, I'll be able to use REST over an unencrypted connection.

Invoke-RestMethod returning 401 - Unauthorized in Powershell 7

I'm running into an issue trying to use the Invoke-RestMethod command in PowerShell 7. I can get it to run fine in PowerShell 5.1, but 7 gives me a 401 - Unauthorized message.
Here's the command for PowerShell 5.1:
Invoke-RestMethod "http://internalServer/api/job?name=testJob" -Method GET -UseDefaultCredentials -ContentType "application/JSON"
Here's the command for PowerShell 7:
Invoke-RestMethod "http://internalServer/api/job?name=testJob" -Method GET -UseDefaultCredentials -ContentType "application/JSON" -AllowUnencryptedAuthentication
The api is hosted on an internal server that uses Windows Authentication. When I track the requests through Fiddler, both commands seem to get the 401 response, but PowerShell 5.1 uses the response to generate an Authorization: Negotiate YII{token} header whereas PowerShell 7 stops and returns an error. Has anyone else encountered this before?
As indicated in the comments, there is a redirect going on here. By default, authentication won't survive a redirect, but you can control that with the -PreserveAuthorizationOnRedirect parameter to Invoke-RestMethod:
$irmParams = #{
Uri = "http://internalServer/api/job?name=testJob"
Method = 'GET'
UseDefaultCredentials = $true
ContentType = 'application/json'
PreserveAuthorizationOnRedirect = $true # <== Should be your solution
AllowUnencryptedAuthentication = $true # <=== You should not be using this :)
}
Invoke-RestMethod #irmParams
Thanks to some additional legwork by OP, -PreserveAuthorizationOnRedirect:
Will only keep the authentication headers for requests made to a Uri that includes the original Uri up to the last /. What the documentation doesn't include is that the subsequent Uri's must also match the case of the original Uri.
In OP's case, the redirection was changing the case of the original Uri, thus breaking the authentication on redirect even when they specified -PreserveAuthorizationOnRedirect.

Trying to create a Devops Agent pool using REST api

I'm trying to create an agent pool (Azure devops Server) using powershell and invoke-restmethod. To do this I'm using the reference below to try a build up a correct json request body.
https://learn.microsoft.com/en-us/rest/api/azure/devops/distributedtask/pools/add?view=azure-devops-rest-5.1
All basics in place (credentials etc - I have successfully run other tasks using other uris)
Many attempts at finding the correct body, all pretty much with the same result, latest example below;
$requestBodyAgentPool = '{
"Id": "3"
"name": "Testpool",
"isHosted": $false,
"autoSize": $false,
"poolType": "automation",
"isLegacy": $false
}'
Using the following (verified the uri and credentials by running a GET)
$uriPool = "http://localhost/DefaultCollection/_apis/distributedtask/pools?api-version=5.1"
Invoke-RestMethod -Uri $uriPool -Method POST -ContentType 'application/json' -Body $requestBodyAgentPool -Credential $cred
Fails with below which to me means the parameter id is null.
Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name: pool.Name","typeName":"System.ArgumentNullException,
mscorlib","typeKey":"ArgumentNullException","errorCode":0,"eventId":0}
I have a feeling this is just my inexperience with coding terms and reading the reference documentation but it is not clear to me if the format is wrong or I'm missing/wrong format a mandatory parameter (id or name?)
Suggest you could use some UI tool such as Postman to verify if you are able to run same Rest API. This will help you narrow down the issue.
{
"name": "{poolname}",
"autoProvision": $true
}
The request body should be a json format. Try to explicitly add ConvertTo-Json for your post body.
More details take a look at Daniel's reply in this link: TFS 2018 Create agent pool programatically

Getting a file from BitBucket Rest API v2.0

I have a script which grabs a file from GIT using the bitbucket REST API (1.0) however it has recently stopped working. I'm theorizing this may be due to the v1 REST API being depreciated but I'm not sure.
Anyway I am trying to retrieve the file using the new 2.0 REST API but I can't seem to get the syntax right as the request continually fails.
I'm starting out with curl since its easiest to test. This is what I'm trying:
curl -u myusername#mydomain.com "https://api.bitbucket.org/2.0/repositories/MyCompany/myrepo/downloads/Scripts/Environment Setup/test.txt"
Enter host password for user 'myusername#mydomain.com': redacted
{"type": "error", "error": {"message": "Resource not found", "detail": "There is no API hosted at this URL.\n\nFor information about our API's, please refer to the documentation at: https://developer.atlassian.com/bitbucket/api/2/reference/"}}
Here is the reference documentation I am using: https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/downloads/%7Bfilename%7D
Maybe I am using the wrong function? I'm not sure.
For posterities sake, you don't want to use the following to download an individual file from bitbucket:
https://api.bitbucket.org/2.0/repositories/MyCompany/myrepo/downloads/path/to/your/file.txt
("Downloads" is to download entire repo files like a .zip file)
Instead you want to do:
curl --user myuser#mydomain.com:password "https://api.bitbucket.org/2.0/repositories/MyCompany/myrepo/src/master/path/to/file.txt"
If you're trying to use Invoke-RestRequest (in powershell) note there are some extra steps. With the old 1.0 API you could do:
$cred = Get-Credential
$uri = "https://api.bitbucket.org/1.0/repositories/MyCompany/$($filepath)"
# Get the files from bitbucket (GIT)
Invoke-RestMethod -Credential $cred -Uri $uri -Proxy $proxyUri -OutFile $destination
With the new 2.0 API that no longer works. Powershell's Invoke-RestMethod waits for a 401 response before sending the credentials, and the new 2.0 bitbucket api never provides one, so credentials never get sent causing a 403 forbidden.
To work around that you have to use the following ugly hack to force Invoke-RestMethod to send the credentials immediately in an Authorization header:
$cred = Get-Credential
$uri = "https://api.bitbucket.org/2.0/repositories/MyCompany/$($filepath)"
$username = ($cred.GetNetworkCredential()).username
$password = ($cred.GetNetworkCredential()).password
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))
# Get the files from bitbucket (GIT)
Invoke-RestMethod -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Uri $uri -Proxy $proxyUri -OutFile $destination
Hopefully that helps someone else out in the future!
Thanks #Jim Redmond for the help.
You can also use the PowerShell module BitbucketServerAutomation. There's not a ton of cmdlets, they do have Get-BBServerFile and Get-BBServerFileContent. I have found it is well written, very usable and being updated regularly. The Invoke-BBServerRestMethod cmdlet is available if you need a command it doesn't have.

getting 203 with error when using vsts rest api

When I'm trying to create a new work item in VSTS with the POST request:
https://galilinetsky.visualstudio.com/Automatiom/_apis/wit/workitems/$Test%20Case?api-version=5.0-preview.2
I get the next response :
Microsoft Internet Explorer's Enhanced Security Configuration is
currently enabled on your environment. This enhanced level of security
prevents our web integration experiences from displaying or performing
correctly. To continue with your operation please disable this
configuration or contact your administrator.
What am I doing wrong?
The solution is to be found in a similar question: Why I get Internet Explorer enhanced security error message in Chrome if I call VSO API from Angularjs SPA?
Andy writes
the PAT has to be prefix[ed] by ":" before you base 64 encode it"
So the solution is:
Create a Personal Access Token
Add a colon (':') before it
Encode the new PAT (with the preceding colon) using Base 64
Et voila ! That PAT will no longer give you a 203 error.
It's mainly caused by the PAT format is incorrect.
Such as if I add colon : before the PAT, the REST API will return with 203.
adding on to #numeratus
This question took awhile for me to get correctly on powershell. https://www.opentechguides.com/how-to/article/azure/201/devops-rest-powershell.html helped me greatly and a resulting simplified powershell request to azure apis
#enter your token in pat token
$pat = "xxx"
# Create header with PAT
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($pat)"))
$header = #{authorization = "Basic $token"}
#enter your url in projects url
$projectsUrl = "https://feeds.dev.azure.com/"
$projects = Invoke-RestMethod -Uri $projectsUrl -Method Get -ContentType "application/json" -Headers $header