I'm changing my Powershell script that updates an applications passwordCredentials (specifically the keyId,secretText and Hint) as previously we used PATCH but this has now changed as per : https://developer.microsoft.com/en-us/graph/blogs/breaking-changes-application-and-serviceprincipal-api-updates-in-microsoft-graph-beta/
However when I use POST I cannot seem to update the KeyId, secretText and Hint anymore, this continues to work with PATCH but was looking to update my code before this goes live, can you assist?
This Code still works at present :
$jsonData = '
{
"passwordCredentials": [
{
"customKeyIdentifier": null,
"endDateTime": "2119-05-01T10:18:33.4995826Z",
"keyId": "'+ $($guid) +'",
"startDateTime": "2019-05-01T10:18:33.4995826Z",
"secretText": "'+ $($Password.Password) +'",
"hint": "'+ $($Passwordhint) +'"
}
]
}'
#Specify the URI to call and method
$uri = "https://graph.microsoft.com/beta/applications/$ID/"
$method = "PATCH"
Invoke-WebRequest -Method $method -Uri $uri -ContentType "application/json" -Body $jsonData -Headers #{Authorization = "$($global:authtoken.authorization)"} -ErrorAction Stop | Out-Null
The following does POST but creates a password with none of the information provided, passwordCredentials are not updated for the application as expected:
#Populate JSON data for the application
$jsonData = '
{
"passwordCredentials": [
{
"customKeyIdentifier": null,
"endDateTime": "2119-05-01T10:18:33.4995826Z",
"keyId": "'+ $($guid) +'",
"startDateTime": "2019-05-01T10:18:33.4995826Z",
"secretText": "'+ $($Password.Password) +'",
"hint": "'+ $($Passwordhint) +'"
}
]
}'
#Specify the URI to call and method
$uri = "https://graph.microsoft.com/beta/applications/$ID/addPassword"
$method = "POST"
Invoke-WebRequest -Method $method -Uri $uri -ContentType "application/json" -Body $jsonData -Headers #{Authorization = "$($global:authtoken.authorization)"} -ErrorAction Stop | Out-Null
It appears the addPassword action from https://graph.microsoft.com/beta/$metadata has a wrapped passwordCredential as a parameter:
...
<Action Name="addPassword" IsBound="true">
<Parameter Name="bindingParameter" Type="microsoft.graph.application" Nullable="false"/>
<Parameter Name="passwordCredential" Type="microsoft.graph.passwordCredential"/>
<ReturnType Type="microsoft.graph.passwordCredential" Nullable="false"/>
</Action>
...
A POST body like this:
{
"passwordCredential": {
"customKeyIdentifier": null,
"endDateTime": "2119-05-01T10:18:33.4995826Z",
"startDateTime": "2019-05-01T10:18:33.4995826Z",
"displayName": "new test password"
}
}
should return a generated credential like:
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#microsoft.graph.passwordCredential",
"customKeyIdentifier": null,
"endDateTime": "2119-05-01T10:18:33.4995826Z",
"keyId": "...",
"startDateTime": "2019-05-01T10:18:33.4995826Z",
"secretText": "...",
"hint": "...",
"displayName": "new test password"
}
Related
We are using Azure Data Lake Gen1 as source in our Tabular model. We have deployed this model on on-prem server. Now, every time we have to manually refresh the credentials to process the model. We want to automate that. I have already tried following link.
https://blog.gbrueckl.at/2017/11/processing-azure-analysis-services-oauth-sources-like-azure-data-lake-store/
But gives following error
credentials provided cannot be used for the DataLake source
This is the credentials object that is getting created from script:
{
"AuthenticationKind": "OAuth2",
"kind": "DataLake",
"path": "https://mydatalake.azuredatalakestore.net/",
"Expires": "Thu, 21 Mar 2020 01:37:50 GMT",
"AccessToken": "",
"RefreshToken": ""
}
Code:
[string] $ClientID = ""
[string] $AASServerName = ""
[string] $AASDatabaseName = ""
[string] $CredentialName =""
[string] $Password = ""
Import-Module SqlServer
$authUrl = "https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/token"
$body = #{
"client_id" = $ClientID;
"scope" = "openid offline_access";
"grant_type" = "password";
"username" = $CredentialName
"password" = $Password
}
Write-Output "Getting Authentication-Token ..."
$adlsToken = Invoke-RestMethod -Uri $authUrl –Method POST -Body $body
$dtformat = "r"
$dateTime = Get-Date -f $dtformat
$newdateTime=[datetime]::ParseExact($datetime,$dtformat,$Null).AddSeconds($adlsToken.expires_in).ToString($dtformat)
#modify the token so it can be used within our ADLS Datasource
$adlsToken | Add-Member -NotePropertyName "AuthenticationKind" "OAuth2"
$adlsToken | Add-Member -NotePropertyName "kind" "DataLake"
$adlsToken | Add-Member -NotePropertyName "path" "https://mydatalake.azuredatalakestore.net/"
$adlsToken | Add-Member -NotePropertyName "Expires" $newdateTime
$adlsToken | Add-Member -NotePropertyName "AccessToken" $adlsToken.access_token
$adlsToken | Add-Member -NotePropertyName "RefreshToken" $adlsToken.refresh_token
$adlsToken = $adlsToken | Select-Object -Property * -ExcludeProperty scope,expires_in,ext_expires_in,token_type, id_token,refresh_token,access_token,token_type
Write-Output "Updating DataSource with latest token ..."
#Update the DataSource with a valid Token
$updateDataSource = '{
"createOrReplace": {
"object": {
"database": "'+$AASDatabaseName+'",
"dataSource": "DataLake/https://mydatalake azuredatalakestore net/xyx/data"
},
"dataSource": {
"type": "structured",
"name": "DataLake/https://mydatalake azuredatalakestore net/xyx/data",
"connectionDetails": {
"protocol": "data-lake-store",
"address": {
"url": "https://mydatalake.azuredatalakestore.net"
}
},
"credential": ' + (ConvertTo-Json $adlsToken) + '
}
}
}'
$updateDataSource
Invoke-ASCmd -Server $AASServerName -Database $AASDatabaseName -Query $updateDataSource
Write-Output "Start Processing <dataOnly> ..."
$processObject = '
{
"refresh": {
"type": "dataOnly",
"objects": [ {"database": "' + $AASDatabaseName + '"} ]
}
}'
Invoke-ASCmd -Server $AASServerName -Database $AASDatabaseName -Query $processObject
Write-Output "Finished!"
Using the Azure DevOps REST API and PowerShell, I am trying to create a very basic Release pipeline. My JSON body works fine in Postman, but errors out when run with Invoke-RestMethod in PowerShell.
I'm following the documentation from https://learn.microsoft.com/en-us/rest/api/azure/devops/build/definitions/create?view=azure-devops-rest-5.0.
Using Postman, I've created a JSON body that works perfectly and repeatedly (provided I either change the release pipeline name or delete the previously created one). I've copied the JSON content verbatim to my PowerShell script, setting the variable $requestBody equal to the JSON content. When I run the script, I get an error (see below for error content).
Following is my test script (apologize for the length, but I thought it important I include the entire JSON.
$organization = "ORGNAME"
$token = "6-OBFUSCATED_TOKEN-a"
$project = "PROJECTNAME"
# Base64-encode the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $token)))
$uri = "https://dev.azure.com/$($organization)/$($project)/_apis/build/definitions?api-version=5.0"
$requestBody = '{
"source": "restAPI",
"revision": 1,
"description": null,
"name": "RepoName-CD",
"path": "\\",
"projectReference": null,
"properties": {},
"environments": [
{
"name": "Stage 1",
"variables": {},
"variableGroups": [],
"preDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false
}
],
"approvalOptions": {
"requiredApproverCount": null,
"releaseCreatorCanBeApprover": false,
"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
"enforceIdentityRevalidation": false,
"timeoutInMinutes": 0,
"executionOrder": "beforeGates"
}
},
"postDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false
}
],
"approvalOptions": {
"requiredApproverCount": null,
"releaseCreatorCanBeApprover": false,
"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
"enforceIdentityRevalidation": false,
"timeoutInMinutes": 0,
"executionOrder": "afterSuccessfulGates"
}
},
"deployPhases": [
{
"deploymentInput": {
"parallelExecution": {
"parallelExecutionType": "none"
},
"skipArtifactsDownload": false,
"artifactsDownloadInput": {
"downloadInputs": []
},
"demands": [],
"enableAccessToken": false,
"timeoutInMinutes": 0,
"jobCancelTimeoutInMinutes": 1,
"condition": "succeeded()",
"overrideInputs": {}
},
"rank": 1,
"phaseType": "agentBasedDeployment",
"name": "Agent job",
"refName": null,
"workflowTasks": []
}
],
"environmentOptions": {
"emailNotificationType": "OnlyOnFailure",
"emailRecipients": "release.environment.owner;release.creator",
"skipArtifactsDownload": false,
"timeoutInMinutes": 0,
"enableAccessToken": false,
"publishDeploymentStatus": true,
"badgeEnabled": false,
"autoLinkWorkItems": false,
"pullRequestDeploymentEnabled": false
},
"executionPolicy": {
"concurrencyCount": 1,
"queueDepthCount": 0
},
"schedules": [],
"retentionPolicy": {
"daysToKeep": 30,
"releasesToKeep": 3,
"retainBuild": true
},
"processParameters": {},
"properties": {},
"environmentTriggers": []
}
]
}'
Invoke-RestMethod -Uri $uri -Method POST -ContentType "application/json" -Headers #{Authorization = ("Basic {0}" -f $base64AuthInfo) } -Body $requestBody
When I run the script, I expected to get back the JSON confirming that the release pipeline was created, but instead I get the following error from PowerShell.
Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name: definition.Repository","typeName":"System.ArgumentNullException,
mscorlib","typeKey":"ArgumentNullException","errorCode":0,"eventId":0}
At C:\GitHub\landingzone\AzureDevOpsApiDev\testmule.ps1:113 char:1
+ Invoke-RestMethod -Uri $uri -Method POST -ContentType "application/js ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Any assistance or guidance will be greatly appreciated.
It looks like you're making a POST to the create build definition API. If you're trying to create a release definition, you probably need to post to a URL like this
POST https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions?api-version=5.0
Well, the lesson here is to not copy and paste code from a previously working script WITHOUT DOUBLE CHECKING IT.
Mea Culpa.
I would like to create a customer by quickbooks API.
First thing everything is working well with a GET request.
But when I try a POST request I get
Error code="100">General Authentication Error
Here's the Oauth2 token =>
at = OAuth2::AccessToken.new(::QB_OAUTH2_CONSUMER, acces_token)
Here's the new_customer =>
new_customer =
{
"BillAddr": {
"Line1": "10 rue Des Champs",
"City": "Paris",
"Country": "FRANCE",
"CountrySubDivisionCode": "FR",
"PostalCode": "75020"
},
"Notes": "Just a test",
"Title": "Mr",
"GivenName": "John",
"MiddleName": "",
"FamilyName": "Doe",
"Suffix": "",
"FullyQualifiedName": "John Doe",
"CompanyName": "DonwtownLA",
"DisplayName": "DonwtownLA",
"PrimaryPhone": {
"FreeFormNumber": "0123456789"
},
"PrimaryEmailAddr": {
"Address": "johndoe#gmail.com"
}
}
Here's the URL =>
at.post("https://quickbooks.api.intuit.com/v3/company/#{realm_id}/customer")
Anyone can help me for this I cant see what I'm doing wrong.
Thanks in advance.
Ok I got It !
Here's the code for creating user from Quickbooks Controller
def create_qb_customer
data =
{
"Notes": "This is from Darta",
"GivenName": "#{params[:first_name]}",
"FamilyName": "#{params[:last_name]}",
"CompanyName": "#{params[:company]}",
"PrimaryEmailAddr": {
"Address": "#{params[:email]}"
}
}
realm_id = QbToken.last.realm_id
url = URI("https://sandbox-quickbooks.api.intuit.com/v3/company/#{realm_id}/customer/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request["Authorization"] = "Bearer #{QbToken.last.serial}"
request["Cache-Control"] = 'no-cache'
request["Postman-Token"] = 'XXXXXX-cf4c-XXXXX-8d7c-XXXXXXXXX'
request.body = data.to_json
response = http.request(request)
p response.read_body
flash.notice = "Your QuickBooks customer is successfully created !"
redirect_to list_all_project_path
end
Please try the call using Postman. The following blog post should be helpful.
https://developer.intuit.com/hub/blog/2017/08/03/quick-start-quickbooks-online-rest-api-oauth-2-0
Please check if you are passing the content-type as 'application/json'.
I have a cURL that works well:
curl -H "Authorization: Token 71e24088d13304cc11f5a0fa93f2a2356fc43f41" -H "Content-Type: application/json" -X POST -d
'{
"reviewer": {"name": "test name", "email": "test#email.com"},
"publication": {"title": "test title", "doi": "xxx"},
"complete_date": {"month": 6, "year": 2015}
}'
https://my.url.com/ --insecure
And would like to use the multi curl from Symfony2 Guzzle
What I tried so far:
$client = new \Guzzle\Http\Client();
$request = $client->post('https://my.url.com/');
$jsonBody = "'{ ";
$jsonBody .= '"reviewer": {"name": "'.$review['name'].'", "email":"'.$review['email'].'"}, ';
$jsonBody .= '"publication": {"title": "';
if ($review['article_title'] != '')
$jsonBody .= $review['article_title'];
else
$toExec .= $review['manuscript_title'];
if ($review['doi'] != '')
$jsonBody .= '", "doi": "'.$review['doi'].'"}, ';
else
$toExec .= '"}, ';
$jsonBody .= '"complete_date": {"month": '.$month.', "year": '.$year.'}';
$jsonBody .= "}' ";
$options = [
'headers' => [ 'Content-Type' => 'application/json', 'Authorization' => 'Token 71e24088d13304cc11f5a0fa93f2a2356fc43f41' ],
'body' => $jsonBody,
];
$request->getCurlOptions()->set(CURLOPT_SSL_VERIFYHOST, false);
$request->getCurlOptions()->set(CURLOPT_SSL_VERIFYPEER, false);
$response = $client->post('-d', $options);
But this doesn't work, I am getting an array as a result which I am not supposed to.
You might try moving your authorization to cURL.
$token = '71e24088d13304cc11f5a0fa93f2a2356fc43f41';
$request->getCurlOptions()->set(CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
$request->getCurlOptions()->set(CURLOPT_USERPWD, "$token:X");
X is the password but often there is none needed so you just add an X (random character)
Running into parseError attempting to follow the "start a resumable session" YouTube Data API - Resumable Uploads documentation.
complete list of efforts ,response and code
I read on the Google APIs - "Global domain errors" page "parseError The API server cannot parse the request body."
I have watched "YouTube Developers Live: Debugging & Dealing with Errors" still know clue there
I have read "stack over flow" for similar questions, but never get answered,or answers are still un clear
the test youtube account i want to upload to has a youtube channel with videos
I tried the client PHP upload API, but found out later its not a resumable upload.
I thought resumable upoad would be a better option, so i dont frustrate users, by wasting there time,if there connection drops out....
I am runing PHP from hostgator account
I noticed how when i did not get an error, it would return the regular snippet and status data and not the "Step 2 - Save the resumable session URI" data
I am using long lived access tokens pulled from my database...in the requests, the youtube user has a channel with videos before i stored the access tokens
I do check the access tokens with tokeninfo?
I noticed changing "uploadType" to "uploadtype" would produce "message": "Media type 'application/json; charset=utf-8'
is not supported. Valid media types: [video/*, application/octet-stream]",following this error by changing content type to "application/octet-stream" would return "kind = youtube#video
object with json snippet,status" not the Step 2 - Save the resumable session URI, so i changed things back to "uploadType" and "application/json; charset=utf-8" now facing same parse error
I notice in the docs "Parameter values in the request URL must be URL-encoded." when i would urlencode() "Parameter values" it would return errors or parseError when i removed the urlencode function
Even changing "Host: www.googleapis.com" to "Host: https://www.googleapis.com" would produce "The requested URL /upload/youtube/v3/videos was not found on this server. That’s all we know."
parse error appears to be most persistent so far
I have changed urlencode() to rawurlencode() still parse error
i would add charset=utf-8;multipart/form-data;application/octet-stream to content type header, still parse error
I notice content type on string is text/plain; charset=us-ascii not sure if google server expects pure application/json
any help would be great…
Array
(
[response] => Array
(
[0] => {
"error": {
"errors": [
{
"domain": "global",
"reason": "parseError",
"message": "Parse Error"
}
],
"code": 400,
"message": "Parse Error"
}
}
)
[headers] => [
"POST \/upload\/youtube\/v3\/videos?uploadType=resumable&part=snippet,status HTTP\/1.1",
"Host: www.googleapis.com",
"Authorization: Bearer ya29.vAAY5n3SJq3uCG7z4tOhehDxYj9Z7mxFENtD5PKF_dJqFlLqwCktRHTrEJkUgY_NrJD3KMetKeBA_w",
"Content-Length: 303",
"Content-Type: application\/json; charset=utf-8",
"X-Upload-Content-Length: 20121",
"X-Upload-Content-Type: video\/*"
]
[curl_resource] => Resource id #18
[video_aray] => {
"snippet": {
"title": "test video",
"description": "testing api",
"tags": [
"any",
"thing"
],
"categoryId": 25
},
"status": {
"privacyStatus": "public",
"embeddable": true,
"license": "youtube"
}
}
[json_requestbody] => {
"snippet": {
"title": "test video",
"description": "testing api",
"tags": [
"any",
"thing"
],
"categoryId": 25
},
"status": {
"privacyStatus": "public",
"embeddable": true,
"license": "youtube"
}
}
[request_url] => https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status
[content_type_of_request] => text/plain; charset=us-ascii
[0] => text/plain; charset=us-ascii
[1] => text/plain; charset=us-ascii
)
Source
public function startResumableSession()
{
$videoResource = array( 'snippet'=>array('title'=>"test video",'description'=>"testing api",
'tags'=>array("any","thing"),'categoryId'=>25),
'status'=>array('privacyStatus'=>"public",'embeddable'=>True,'license'=>"youtube"));
$requestBody = json_encode($videoResource,JSON_PRETTY_PRINT);
$headers = array
(
"POST /upload/youtube/v3/videos?uploadType=resumable&part=snippet,status HTTP/1.1",
"Host: www.googleapis.com",
"Authorization: Bearer ya29.vAAY5n3SJq3uCG7z4tOhehDxYj9Z7mxFENtD5PKF_dJqFlLqwCktRHTrEJkUgY_NrJD3KMetKeBA_w",
"Content-Length: ".strlen($requestBody),
"Content-Type: application/json; charset=utf-8",
"X-Upload-Content-Length: 20121",
"X-Upload-Content-Type: video/*"
);
/* Parameter values in the request URL must be URL-encoded. */
$url = "https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch, CURLOPT_POSTFIELDS,urlencode($requestBody));
curl_setopt($ch, CURLOPT_RETURNTRANSFER,TRUE);
$result = curl_exec($ch);
$json = json_decode($result);
/* Check request body contenttype */
$finfo = new finfo(FILEINFO_MIME);
$t1= $finfo->buffer($requestBody);
$t2 = $finfo->buffer("test");
$t3 = $finfo->buffer(utf8_encode("test"));
/* debug info */
return array( 'response'=>(array)$result,
'headers'=>json_encode($headers,JSON_PRETTY_PRINT),
'curl_resource'=>$ch,
'video_aray'=>json_encode($videoResource,JSON_PRETTY_PRINT),
'json_requestbody'=>$requestBody,
'request_url'=>$url,
'content_type_of_request'=>$t1,$t2,$t3
);
}
Easy answer is - you do it wrong.
You are NOT supposed to add "POST", "Host:" and "Content-Length:" into $headers because that is generated by curl (CURLOPT_URL and CURLOPT_POSTFIELDS).
YouTube API works correctly. It is not their fault.