Azure DevOps REST API returns a 403 when using the system OAuth token during a build - azure

I'm running a script:
# Variables
$organization = "****"
$project = "****"
$repositoryId = "****"
$pullRequestId = $env:BUILD_PULLREQUEST_ID
$pat = "Bearer $env:System_AccessToken"
$featureReleaseUrl = "http://" + $env:prSourceBranchName + ".azurewebsites.net"
$body = #"
{
"comments": [
{
"content": "Link naar feature release $featureReleaseUrl"
}
]
}
"#
$createThreadInPRUrl = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$repositoryId/pullRequests/$pullRequestId/threads?api-version=5.0"
if ($pullRequestId) {
Invoke-RestMethod -Uri $createThreadInPRUrl -Headers #{Authorization = $pat} -Body $body -Method Post -ContentType 'application/json'
}
When it runs it returns a:
##[error]The remote server returned an error: (403) Forbidden.
I've created a Personal Access Tokens in my personal settings.
I've also created this script:
# Variables
$organization = "****"
$project = "****"
$buildId = $****
$pat = "Bearer $env:System_AccessToken"
if (!$env:Build_PullRequest_SourceBranchName) {
$retrieveSourceBranchFromBuildURL = "https://dev.azure.com/$organization/$project/_apis/build/builds/$buildId" + "?api-version=5.0"
$buildInformation = Invoke-RestMethod -Uri $retrieveSourceBranchFromBuildURL -Headers #{Authorization = $pat } -Method Get -ContentType 'application/json'
$SourceBranchFromBuild = $buildInformation.sourceBranch.split('/')[-1]
Write-Host "### no Build PullRequest SourceBranchName available ###"
Write-Host "##vso[task.setvariable variable=prSourceBranchName;]"$SourceBranchFromBuild
}
And this runs fine. The difference between the first and second script is that the first is a POST and the second a GET. But they both use the $pat token.

Even though the token you used is System.AccessToken, if you don't have access permission of Pull Request, you will also could not operate it.
Go Project Setting--> Repositories--> Repository you want to access, locate your account or the group you are in. Check the permission state of Contribute to pull requests.
You must have this Contribute to pull requests permission allowed, so that you can add the comment to PR.

Related

Azure Devops REST API SendMail

I'm trying to send mail after the successful stage on my release definition.
Following the docs
OAuth box is checked in my stage
Project Collection Service Account is added to Build Administrators and Release Administrators.
But the response from REST API is "Azure DevOps Login Page"
Here is my script:
$OrganizationName = "myorg"
$ProjectName = "myproj"
$sendmailto = "example#mail.com"
$mysubject = "Test Mail Subjcet"
$mailbody = "Mail body to test it works with azure rest api"
$PAT="MYPAT"
$Token = "$(System.AccessToken)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$Token"))
$HeaderMail = #{
Authorization = "Bearer $encodedCreds"
}
##send mail
$urimail = "https://${OrganizationName}.vsrm.visualstudio.com/${ProjectName}/_apis/Release/sendmail/$($env:RELEASE_RELEASEID)?api-version=3.2-preview.1"
$requestBody =
#"
{
"senderType":1,
"to":{"tfsIds":[$sendmailto]},
"body":"${mailbody}",
"subject":"${mysubject}"
}
"#
Try {
Invoke-RestMethod -Uri $urimail -Body $requestBody -Method POST -ContentType "application/json" -Headers $HeaderMail
}
Catch {
$_.Exception
}
Tested with:
Tried with 3.2 version and 7.1
PAT Token and authorization to Basic return 400 with Bearer return 401.
Switch $(System.AccessToken) to $($env:System_AccessToken) trygin to convert to base64 and without.
What I'm missing?
Response from
ConsoleLog
It's caused by the $requestBody. The request body requires valid Azure DevOps users referenced by their tfsIds.
Below PS script works for me, if your are running it in pipeline, then please use the $(System.AccessToken) instead of $PAT.
Running locally and authenticate with PAT:
$OrganizationName = "organization"
$ProjectName = "Project"
$sendmailto = "xxx#microsoft.com"
$mysubject = "Test Mail Subjcet"
$PAT="xxx"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$PAT"))
$HeaderMail = #{
Authorization = "Basic $encodedCreds"
}
#Get the tfsid
$userentitlementurl = "https://vsaex.dev.azure.com/${OrganizationName}/_apis/userentitlements?api-version=7.1-preview.1"
$response = Invoke-RestMethod -Uri $userentitlementurl -Method Get -Headers $HeaderMail
#Filter by sendmailto
$tfsid = ($response.value| where {$_.user.mailAddress -eq $sendmailto}).id
Write-Host $tfsid
##send mail
$urimail = "https://vsrm.dev.azure.com/${OrganizationName}/${ProjectName}/_apis/Release/sendmail/168?api-version=7.1-preview.1"
$requestBody =
#"
{
"senderType": 1,
"to": {
"tfsIds": [
"$tfsid"
],
"emailAddresses": []
},
"subject": "$mysubject",
"sections": [
5,
0,
1,
2,
4
]
}
"#
Try {
Invoke-RestMethod -Uri $urimail -Body $requestBody -Method POST -ContentType "application/json" -Headers $HeaderMail
}
Catch {
$_.Exception
}
Running in release pipeline and authenticate with $(System.AccessToken): (Please note that, because this script is being run during the release, the summary email will show the environment as IN PROGRESS even if it is run as the last step in the Release.)
$OrganizationName = "organization"
$ProjectName = "project"
$sendmailto = "xxx#microsoft.com"
$mysubject = "Test Mail Subjcet"
$HeaderMail = #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
#Get the tfsid
$userentitlementurl = "https://vsaex.dev.azure.com/${OrganizationName}/_apis/userentitlements?api-version=7.1-preview.1"
$response = Invoke-RestMethod -Uri $userentitlementurl -Method Get -Headers $HeaderMail
#Filter by sendmailto
$tfsid = ($response.value| where {$_.user.mailAddress -eq $sendmailto}).id
Write-Host $tfsid
##send mail
$urimail = "$env:SYSTEM_TEAMFOUNDATIONSERVERURI$env:SYSTEM_TEAMPROJECT/_apis/Release/sendmail/$($env:RELEASE_RELEASEID)?api-version=7.1-preview.1"
$requestBody =
#"
{
"senderType": 1,
"to": {
"tfsIds": [
"$tfsid"
],
"emailAddresses": []
},
"subject": "$mysubject",
"sections": [
5,
0,
1,
2,
4
]
}
"#
Try {
Invoke-RestMethod -Uri $urimail -Body $requestBody -Method POST -ContentType "application/json" -Headers $HeaderMail
}
Catch {
$_.Exception
}

Azure REST API list key vault secrets has maxresults limited to 25

I'm trying to get a list of all the secrets in each of my key vaults and I'm using Microsofts documentation at this URL.
https://learn.microsoft.com/en-us/rest/api/keyvault/getsecrets/getsecrets#secretlistresult
It states that if you do not set maxresults it will default to 25. It does however throw this error in my powershell script when i try to set it higher than 25.
{"error":{"code":"BadParameter","message":"invalid maxresults"}}
From the documentation the endpoint does not appear to contain any pagination or way to get more than 25 random secrets. This seems to make the endpoint pretty useless as there are no ways to filter the listings.
The command I'm using to get the list is this.
$uri = ""https://$($Vault).vault.azure.net/secrets?api-version=7.1&maxresults=26""
Invoke-RestMethod -Method Get -Uri $uri -Headers $headers
As Gaurav said in the comment, you need to use nextLink to get the result of next page.
There is my test code with do-until:
$LoginUrl = "https://login.microsoft.com"
$RresourceUrl = "https://vault.azure.net/.default"
$ClientID = ""
$ClientSecret = ""
$TenantName = ""
# Compose REST request.
$Body = #{ grant_type = "client_credentials"; scope = $RresourceUrl; client_id = $ClientID; client_secret = $ClientSecret }
$OAuth = Invoke-RestMethod -Method Post -Uri $LoginUrl/$TenantName/oauth2/v2.0/token -Body $Body
# Check if authentication was successfull.
if ($OAuth.access_token) {
# Format headers.
$HeaderParams = #{
'Content-Type' = "application\json"
'Authorization' = "Bearer $($OAuth.access_token)"
}
# Create an empty array to store the result.
$QueryResults = #()
$Uri = "https://<your-key-vault-name>.vault.azure.net/secrets?api-version=7.1"
# Invoke REST method and fetch data until there are no pages left.
do {
$Results = Invoke-RestMethod -Headers $HeaderParams -Uri $Uri -UseBasicParsing -Method "GET" -ContentType "application/json"
$Results.nextLink
if ($Results.value) {
$QueryResults += $Results.value
}
else {
$QueryResults += $Results
}
$Uri = $Results.nextLink
} until (!($Uri))
# Return the result.
$QueryResults
}
else {
Write-Error "No Access Token"
}

How to add team members in Azure Devops via API? Also Groups API does not work

I am new to Azure Devops and currently migrating to it. I want to add team members for my azure project via REST API. I referred the following documentation, but there is no mention of it. 'Teams' API has no functionality to add Members to it, rather only to create a Team with the Team Name of your choice.
https://learn.microsoft.com/en-us/rest/api/azure/devops/?view=azure-devops-rest-5.1
I encountered another problem in the Group Entitlements API:
https://learn.microsoft.com/en-us/rest/api/azure/devops/memberentitlementmanagement/group%20entitlements/list?view=azure-devops-rest-5.1
I am unable to hit this particular URL: https://vsaex.dev.azure.com.
In the other API examples, they have used only https://dev.azure.com which works perfectly fine for me. I do not understand what the vsaex stands for. Adding 'vsaex' or ignoring it did not work either. I could not find any documentation regarding this.
Same problem arises for vsaex.dev.azure.com for Users API.
Solutions to any of these would be helpful. Thanks in advance :)
I recently write a PowerShell Script to solve your first problem, but it is only tested on a local azure devops server.
class REST {
#PROPERTIES
[string]$ContentType = "application/json;charset=utf-8"
[string]$PAT
[System.Collections.IDictionary]$Headers
[string]$Url
[string]$Collection
[string]$_Project
#STATIC PROPERTIES
static [int]$Timeout = 30
#CONSTRUCTOR
REST([string]$PAT, [string]$Url, [string]$Collection, [string]$Project) { $this.Init($PAT, $Url, $Collection, $Project) }
REST([string]$PAT, [string]$Url, [string]$Collection) { $this.Init($PAT, $Url, $Collection, $null) }
REST([string]$PAT, [string]$Url) { $this.Init($PAT, $Url, $null, $null) }
REST([string]$PAT) { $this.Init($PAT, $null, $null, $null) }
#INITIALIZE
[void]Init([string]$PAT, [string]$Url, [string]$Collection, [string]$Project) {
$this.PAT = $PAT
$this.Url = $Url
$this.Collection = $Collection
$this._Project = $Project
$this.Headers = $(Headers -PAT $PAT)
}
#GET
[PSCustomObject]Get([string]$Uri) { return Invoke-RestMethod -Uri $Uri -Method GET -ContentType $this.ContentType -Headers $this.Headers -TimeoutSec $([REST]::Timeout) -Verbose }
#PUT
[PSCustomObject]Put([string]$Uri, $Body) { return Invoke-RestMethod -Uri $Uri -Method PUT -ContentType $this.ContentType -Headers $this.Headers -Body $Body -TimeoutSec $([REST]::Timeout) -Verbose }
#POST
[PSCustomObject]Post([string]$Uri, $Body) { return Invoke-RestMethod -Uri $Uri -Method POST -ContentType $this.ContentType -Headers $this.Headers -Body $Body -TimeoutSec $([REST]::Timeout) -Verbose }
#DELETE
[PSCustomObject]Delete([string]$Uri) { return Invoke-RestMethod -Uri $Uri -Method DELETE -ContentType $this.ContentType -Headers $this.Headers -TimeoutSec $([REST]::Timeout) -Verbose }
#TEAMS
[PSCustomObject]Teams([string]$Url, [string]$Collection, [string]$Project) { return $($this.Get($(Combine #($Url, $Collection, $Project, "_settings/teams?__rt=fps&__ver=2")))).fps.dataProviders.data.'ms.vss-tfs-web.team-data' }
[PSCustomObject]Teams([string]$Collection, [string]$Project) { return $this.Teams($this.Url, $Collection, $Project) }
[PSCustomObject]Teams([string]$Project) { return $this.Teams($this.Url, $this.Collection, $Project) }
[PSCustomObject]Teams() { return $this.Teams($this.Url, $this.Collection, $this._Project) }
#TEAM MEMBERS
[PSCustomObject]TeamMembers([string]$Url, [string]$Collection, [string]$Project, [string]$TeamId) { return $this.Get($(Combine #($Url, $Collection, $Project, "_api/_identity/ReadGroupMembers?__v=5&scope=$($TeamId)&readMembers=true&scopedMembershipQuery=1"))) }
[PSCustomObject]TeamMembers([string]$Collection, [string]$Project, [string]$TeamId) { return $this.TeamMembers($this.Url, $Collection, $Project, $TeamId) }
[PSCustomObject]TeamMembers([string]$Project, [string]$TeamId) { return $this.TeamMembers($this.Url, $this.Collection, $Project, $TeamId) }
[PSCustomObject]TeamMembers([string]$TeamId) { return $this.TeamMembers($this.Url, $this.Collection, $this._Project, $TeamId) }
#TEAM MEMBER POST
[PSCustomObject]TeamMemberPost([string]$Url, [string]$Collection, [string]$Project, [string]$TeamId, [string]$Domain, [string]$Name) { $body = '{{''newUsersJson'':''[\''{0}\\\\{1}\'']'',''existingUsersJson'':''[]'',''groupsToJoinJson'':''[\''{2}\'']'',''aadGroupsJson'':''[]''}}' -f ($Domain, $Name, $TeamId); return $this.Post($(Combine #($Url, $Collection, $Project, "_api/_identity/AddIdentities?__v=5")), $body) }
[PSCustomObject]TeamMemberPost([string]$Collection, [string]$Project, [string]$TeamId, [string]$Domain, [string]$Name) { return $this.TeamMemberPost($this.Url, $Collection, $Project, $TeamId, $Domain, $Name) }
[PSCustomObject]TeamMemberPost([string]$Project, [string]$TeamId, [string]$Domain, [string]$Name) { return $this.TeamMemberPost($this.Url, $this.Collection, $Project, $TeamId, $Domain, $Name) }
[PSCustomObject]TeamMemberPost([string]$TeamId, [string]$Domain, [string]$Name) { return $this.TeamMemberPost($this.Url, $this.Collection, $this._Project, $TeamId, $Domain, $Name) }
}
These are the REST-API calls I used for.
#TEAMS returns all teams of a project as json. The call also gives you the $TeamId
#TEAM MEMBERS give you all members of a team
#TEAM MEMBER POST allows you to add you new members. Important: the members must be known by Azure DevOps, that means they need to be in your domain (I don't know how it is organized in azure devops service)
How to use: (but this in the same file like the REST class or load the REST class as module or file before)
#ADD = LIST OF VALID AND KNOWN MEMBERS OF YOUR AZURE DEVOPS SERVICE (STORE IT IN A .TXT FILE OR SOMETHING)
$ADD = #("member1#xyz.com", "member2#xyz.com")
#INITIALIZE REST API
$REST = [REST]::new($PAT, $Uri, $Collection, $Project) #$PAT ~ "atfghfrhfdgdwnx6jnyrculcmaas2g5j6rrogpmn7aza266hrudsahq"; $Uri = https://server.com
#REQUEST TEAMS
$result = $REST.Teams()
$team = $result.team
#REQUEST TEAM MEMBERS
$result = $REST.TeamMembers($team.id)
$members = $result.identities.MailAddress
#ADD MISSING MEMBERS TO TEAM
foreach ($item in $ADD) {
if (-not $members.Contains($item)) {
Write-Host "[ps1] add: '$item'" -ForegroundColor Yellow
#POST ADD MEMBER
$name = $item.Replace($mail, "")
$result = $REST.TeamMemberPost($team.id, $domain, $name)
if ("AddedIdentities" -in $result.PSobject.Properties.Name) { Write-Host "[ps1] successful added: $($result.AddedIdentities.DisplayName) ($($result.AddedIdentities.TeamFoundationId))" -ForegroundColor Green }
else { Write-Host "[ps1] fail to add: '$name'" -ForegroundColor Red }
}
}
I take the snippts from my script. I don't have the time to test this stuff, so please expect errors.
How to find out the correct URLs by your self:
Open Browser (I used Edge)
Press F12
Go to Network
Navigate to the event you want to observe
Clear the list
Execute the event (click button)
Check out the GET/POST with application/json like in sceen shot:
If it is a GET/POST Event you can display the the transfered json under text
{
"newUsersJson": "[\"Domain\\\\user\"]",
"existingUsersJson": "[]",
"groupsToJoinJson": "[\"2d1dfa03-a108-4421-958a-bdsfdsf161696\"]",
"aadGroupsJson": "[]"
}
Hope this helps.
You can use member add api to user to team members.
PUT https://vsaex.dev.azure.com/{organization}/_apis/GroupEntitlements/{groupId}/members/{memberId}?api-version=5.1-preview.1
When you go to the Permissions under Project Settings, You will find the team is actually listed as a group. So i tried using team Id for the groupId in above api. And it worked.
After testing,the memeberId is actually the user id.
You can get the user id with below Get User Entitlements api: check here for details.
GET https://vsaex.dev.azure.com/{organization}/_apis/userentitlements?top={top}&skip={skip}&filter={filter}&sortOption={sortOption}&api-version=5.1-preview.2
Then you can call above member add api to add user to teams.
$uri ="https://vsaex.dev.azure.com/{ORG}/_apis/GroupEntitlements/{teamid}/members/{userid}?api-version=5.1-preview.1"
$connectionToken="PAT"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
# Invoke the REST call and capture the results (notice this uses the PATCH methodg
$result = Invoke-RestMethod -Uri $group -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method put
If you cannot hit https://vsaex.dev.azure.com. You may need to check if your {PAT} has the all the permission scopes to perform add member action. Check here for more information about PAT.
There is a lack of information about vsaex. but i guess vsaex is the server domain for user ad data. As Microsoft manage user ad data information in a separate server from other data.
Not 100% an answer to your question, but maybe it can help you or other people.
Recently I had to add user to a team in an AzDo project. I had the email for the users and the name of the team.
I used the following Powershell code in AzDo version M183_20210320.1:
$PAT = "my-path"; # get your Personal access token https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page
$Headers += #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($PAT)")) };
$Collection = 'my-organisation';
$Project = 'my-project';
$Timeout = 30;
$TeamToAddUser = "my-team-name>";
$EmailToAddToTeam = "my#email.com";
# get project id
$ProjectId = (Invoke-RestMethod -Uri "https://dev.azure.com/$($Collection)/_apis/projects/$($Project)?api-version=6.0" -Method GET -ContentType "application/json;charset=utf-8" -Headers $Headers -TimeoutSec $Timeout).id;
Write-Host "ProjectId: $ProjectId";
# get project descriptor
$ProjecDescriptor = (Invoke-RestMethod -Uri "https://vssps.dev.azure.com/$($Collection)/_apis/graph/descriptors/$($ProjectId)?api-version=6.0-preview" -Method GET -ContentType "application/json;charset=utf-8" -Headers $Headers -TimeoutSec $Timeout).value;
Write-Host "ProjecDescriptor: $ProjecDescriptor";
# get all teams in project
$TeamsInProject = (Invoke-RestMethod -Uri "https://vssps.dev.azure.com/$($Collection)/_apis/graph/groups?scopeDescriptor=$($ProjecDescriptor)&api-version=6.0-preview" -Method GET -ContentType "application/json;charset=utf-8" -Headers $Headers -TimeoutSec $Timeout).value;
Write-Host "TeamsInProject: $($TeamsInProject | forEach { "`n - $($_.displayName) : $($_.descriptor)" }) `n";
# get the team
$Team = $TeamsInProject | Where-Object { $_.displayName -eq $TeamToAddUser }
Write-Host "Team: $($Team.displayName) : $($Team.descriptor)";
# get user id from email
$User = (Invoke-RestMethod -Uri "https://vsaex.dev.azure.com/$($Collection)/_apis/userentitlements?api-version=6.0-preview.3&`$filter=name eq '$(${EmailToAddToTeam})'" -Method GET -ContentType "application/json;charset=utf-8" -Headers $Headers -TimeoutSec $Timeout).members[0];
Write-Host "User to add user: $($User.user.displayName) : $($User.user.originId)";
# add user to team
$body = #{
"originId" = $User.user.originId
};
$result = (Invoke-RestMethod -Uri "https://vssps.dev.azure.com/$($Collection)/_apis/graph/Users?groupDescriptors=$($Team.descriptor)&api-version=6.0-preview" -Method POST -ContentType "application/json;charset=utf-8" -Headers $Headers -Body $($body | ConvertTo-Json -Depth 10 -Compress) -TimeoutSec $Timeout)
After spending hours to do this via API I found a solution, You can use
POST https://vssps.dev.azure.com/{organization}/_apis/graph/users?groupDescriptors={groupDescriptor}&api-version=6.0-preview.1
you can add email in a requestbody, JSON will look like
{
"principalName": "yourmail#goeshere.com"
}
For getting the group descriptor use below GET call
GET https://vssps.dev.azure.com/{organization}/_apis/graph/groups?api-version=6.0-preview.1
Check for group with "displayName" as "{your project name} Team" in the response and take group descriptor of that group.
If you are using Postman to make this call, select basic Auth as authorization and give username empty and password as the PAT token.

How to authenticate for https://management.azure.com api?

I want to retrieve data on my DNS zones through a API call:
$api = "?api-version=2018-05-01"
$pat = "Bearer $env:System_AccessToken"
Write-Host "### PAT ###"
Write-Host $pat
$DNSInformation = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Network/dnsZones/$zoneName/$recordType/$relativeRecordSetName$api"
Write-Host "###"
Write-Host $DNSInformation
Write-Host "###"
$x = Invoke-RestMethod -Uri $DNSInformation -Headers #{Authorization = $pat } -Method Get
When I run this script I get:
The remote server returned an error: (401) Unauthorized.
When I navigate to the URL I get:
error: {
code: "AuthenticationFailed",
message: "Authentication failed. The Authorization header is missing."
}
I think the issue is that I can't use the $env:System_AccessToken token to get on the management api. But I can't find information what kind of authentication is needed.
As the error mentions, the authorization header is incorrect.
$URI = "https://management.azure.com/providers/microsoft.resources/checkresourcename?api-version=2014-01-01"
Invoke-RestMethod -Uri $URI -Method GET -Headers $authHeader
You can use a couple of approaches to create your header:
As you mentioned - Azure Powershell to check resource names
By creating Bearer token : Powershell Script to delete unused resources in Azure

How to add Extension Properties for Azure-AD Device Objects using PowerShell?

I want to add extension properties for device objects in Azure AD using Power-Shell. I have search a lot but found examples for only User objects.I have written a script and its successful for User Objects but am not be able to set extension properties for Device.
A command Set-AzureADUserExtension
exists for User but for devices, there is no such commands e.g
Set-AzureADDeviceExtension
(there is no command exists like it). Can anyone help me how to achieve this?How can i set extension properties for Device Objects?
I want to achieve something like this:
New-AzureADApplicationExtensionProperty -ObjectId $MyApp -Name "MyNewProperty" -DataType "String" -TargetObjects "Device";
Set-AzureADDeviceExtension -ObjectId $deviceId -ExtensionName "extension_0380f0f700c040b5aa577c9268940b53_MyNewProperty" -ExtensionValue "MyNewValue";
I was looking for exactly the same and I did not find anything then and today either. I had to use the Microsoft Graph API to add new extensions to the device object. The same for consulting.
Step 1: Install or import the azure module.
Install-Module AzureAD
or
Import-Module AzureAD
Step 2: Search Object and save ObjectID.
$ObjectID = (Get-AzureADDevice -SearchString 'Object-Name').ObjectId
Note: The "id" in the request is the "id" property of the device, not the "deviceId" property.
Step 3: Create App
https://portal.azure.com - Azure Active Directory - App registrations - New registration
Name: YourAppName
Supported account types: Accounts in this organizational directory only (Default Directory)
Redirect URI: (WEB) https://login.microsoftonline.com/common/oauth2/nativeclient
Step 4: Configure App
https://portal.azure.com - Azure Active Directory - App registrations - YourAppName
Certificates & secrets - New client secret
Save client secret value
API permissions - Add a permission - Microsoft Graph - Delegated permissions
Directory.AccessAsUser.All
Step 5: Get access_token
## Directory.AccessAsUser.All : Minimun privilege for Get, add, update and delete extensions. (https://learn.microsoft.com/en-us/graph/api/opentypeextension-post-opentypeextension?view=graph-rest-1.0)
$scopes = "Directory.AccessAsUser.All"
$redirectURL = "https://login.microsoftonline.com/common/oauth2/nativeclient"
$clientID = "YourAppIdClient"
$clientSecret = [System.Web.HttpUtility]::UrlEncode("YourAppClientSecret")
$authorizeUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
$requestUrl = $authorizeUrl + "?scope=$scopes"
$requestUrl += "&response_type=code"
$requestUrl += "&client_id=$clientID"
$requestUrl += "&redirect_uri=$redirectURL"
$requestUrl += "&response_mode=query"
Write-Host
Write-Host "Copy the following URL and paste the following into your browser:"
Write-Host
Write-Host $requestUrl -ForegroundColor Cyan
Write-Host
Write-Host "Copy the code querystring value from the browser and paste it below."
Write-Host
$code = Read-Host -Prompt "Enter the code"
$body = "client_id=$clientID&client_secret=$clientSecret&scope=$scopes&grant_type=authorization_code&code=$code&redirect_uri=$redirectURL"
$tokenUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
$response = Invoke-RestMethod -Method Post -Uri $tokenUrl -Headers #{"Content-Type" = "application/x-www-form-urlencoded"} -Body $body
$token = $response.access_token
Get Extensions device
$apiUrl = 'https://graph.microsoft.com/v1.0/devices/<ID-Object>/extensions' ## change <ID-Object> for your ObjectID.
(https://learn.microsoft.com/en-us/graph/api/device-get?view=graph-rest-1.0&tabs=cs)
$Data = Invoke-RestMethod -Headers #{Authorization = "Bearer $accessToken"} -Uri $apiUrl -Method Get
$Data.Value | fl
Add extensions device
$apiUrl = 'https://graph.microsoft.com/v1.0/devices/<ID-Object>/extensions'
$body = '{
"#odata.type": "microsoft.graph.openTypeExtension",
"id": "test.extension",
"name_extension": "example"
}'
Invoke-RestMethod -Headers #{Authorization = "Bearer $token"; "Content-type" = "application/json"} -Uri $apiUrl -Method Post -Body $body
Update extensions device
## Actualizar datos de una extensión
$apiUrl = 'https://graph.microsoft.com/v1.0/devices/<ID-Object>/extensions/test.extension' ## Extension ID to update
$body = '{
"#odata.type": "microsoft.graph.openTypeExtension",
"id": "test.extension",
"name_extension": "new_value"
}'
Invoke-RestMethod -Headers #{Authorization = "Bearer $token"; "Content-type" = "application/json"} -Uri $apiUrl -Method Patch -Body $body
Delete extensions device
$apiUrl = 'https://graph.microsoft.com/v1.0/devices/<ID-Object>/extensions/test.extension'
Invoke-RestMethod -Headers #{Authorization = "Bearer $token"; "Content-type" = "application/json"} -Uri $apiUrl -Method Delete

Resources