Trying to create a Devops Agent pool using REST api - powershell

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

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.

How do I format the POST or PUT request for a new Repo in Bitbucket API with Powershell?

I've got the documentation for creating a new repo in Bitbucket here
Based on what I saw, I decided to write it up in powershell so I could run this as a script. The only issue is that despite sending a body that I convert to json, it ignores my body and creates the repo as if I had sent no body.
my request:
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization' , "$apiKey")
$headers.Add('accept', 'application/json')
$newRepoRequestBody=#"
{
"scm": "git",
"description": "I scripted this into existence. yay!",
"project": {
"key": "MYKEY"
},
"is_private": true
}
"#
$newRepoRequestBody = $newRepoRequestBody | ConvertTo-Json
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-RestMethod -Method PUT -Headers $headers -Body $newRepoRequestBody -Uri https://api.bitbucket.org/2.0/repositories/$workspace/$repoName -Verbose -UseBasicParsing
When I look at the request response it shows a 200 success, but it does not change the repo to private, nor does it place it under the project key I specified. The json output shows the oldest project key in my workspace.
I tried this in fiddler as well and got the same response. This leads me to believe that it is ignoring the body of my request.
Is my only option to use curl as shown in the docs? Please let me know what I need to correct.

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.

Update AzureAD/O365 UPN via Graph

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.

What's the best way to post data to Elastic Search using powershell?

Should I use convert-tojson or roll my own. Should I use invoke-restrequest, invokeweb-request, System.net.WebClient or system.net.http.HttpClient?
Sometimes I seem to post successfully, although the data isn't indexed.
{"_index":"dropstorage","_type":"connectionstats","_id":"97e156a5-4d16-48d4-84e8-fcc723aea1ae",
"_version":1,"found":true,"_source":{
"hnas": 1,
"active": 70,
"id": "97e156a5-4d16-48d4-84e8-fcc723aea1ae",
"total": "70",
"date": "4/9/2015 9:03:36 AM"
}}
I would recommend the following approach:
$body = ConvertTo-Json $curatorResult -Compress
Invoke-RestMethod -Method Post -Uri $uri -ContentType 'application/json'-Body $body -ErrorAction Stop | Out-Null
Here is a walkthrough for using Elasticsearch from first-principles using PowerShell. There are notes on when to use GET and POST, how to do serialization, mass data generation, and how to interact with many calls directly.
Near the start, you'll find a discussion of making PowerShell calls compatible with Elasticsearch (yes, there's a trick).
Learning Elasticsearch with PowerShell
Check out Elastic.Console, a small PowerShell module for working with Elasticsearch using PowerShell and PowerShell Core. It offers autocompletion on API endpoint paths and methods for a chosen Elasticsearch version.
After installing with
Install-Module -Name Elastic.Console -AllowPrerelease
You can send data with
$body = ConvertTo-Json $curatorResult -Compress
$response = es -Method POST "/{index}/_doc/{id}" -Body $body
The request body can be a JSON string literal, a Hashtable, or a path to a file containing JSON.
Run the following to see full docs and examples
Get-Help es -Full