I have a Powershell script that calls a Google App Script function.
When I run the Powershell script I can see the following error on the Error Reporting on my GCP project:
Exception: You do not have permission to call SpreadsheetApp.getActiveSpreadsheet. Required permissions: (https://www.googleapis.com/auth/spreadsheets.currentonly || https://www.googleapis.com/auth/spreadsheets)
at toSpreadsheet (Código:3)
at fromPS (Código:14)
I have understood that I have to authorize the scope, so I've been trying to do that by editing the manifest file.
The Authorization Scopes Documentation says,
"During the authorization flow, Apps Script presents human-readable descriptions of the required scopes to the user. For example, if your script needs read-only access to your spreadsheets, the manifest may have the scope https://www.googleapis.com/auth/spreadsheets.readonly. During the authorization flow, a script with this scope asks the user to allow this application to "View your Google Spreadsheets"."
In my case I edited the manifest file appscript.json to add the scope https://www.googleapis.com/auth/spreadsheets, then I saved it, published the Google App Script project as API Executable, and finally I run the Powershell code again, but I still get the same error as above. During all this flow, I was not asked to allow anything. I cannot understand what is missing authorizing the script have the required permission.
I also added the spreadsheets scope to OAuth consent screen, but it seems to do not make any difference. I am suspecting I should use a Service Account to accomplish that since I see no way to go through a OAuth Client Verification since my script on Google is called from Powershell script. I dont want to believe on that because getting to know how config OAuth2 took me a lot of time :(
A few considerations:
The function that the run method calls by Powershell just works fine when I run it directly from Google Script Editor.
The script project is deployd as an API executable
Google Apps Script API is enabled in the GCP project
It is associated to a Standard GCP project
The OAuth credential is Web Application type
The script for writing and reading values from Powershell to Google Sheets works fine
Google script:
function toSpreadsheet(text2write)
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("HIL_APP");
var LastRow = sheet.getLastRow();
for (var i = 1; i < LastRow; i++)
{
sheet.getRange(i+1, 8, 1).setValue(text2write)
}
return "myreturn"
}
function fromPS(params)
{
Logger.log(params)
var rtn = toSpreadsheet(params)
return rtn
}
manifest file:
{
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets"
],
"timeZone": "America/Argentina/Buenos_Aires",
"dependencies": {
},
"webapp": {
"access": "ANYONE",
"executeAs": "USER_DEPLOYING"
},
"exceptionLogging": "STACKDRIVER",
"executionApi": {
"access": "MYSELF"
},
"runtimeVersion": "V8"
}
Powershell code:
function doit{
$json = ".\client_id.json"
$jdata = get-content $json | convertfrom-json
<#
$jdata | ForEach-Object {
$_.PSObject.Properties.Value
}
#>
$ClientID = $jdata.web.client_id.ToString()
$ClientSecret = $jdata.web.client_secret.ToString()
$refreshToken = "1//04VvG_FTyDGhiCgYIARAAGAQSNwF-L9IrZ-o1kaZQQccvzL5m4TUTNz6b9Q4KCb16t4cH11gGCshWZWvgaCoMlg73FgpLAGOYTEk"
$grantType = "refresh_token"
$requestUri = "https://accounts.google.com/o/oauth2/token"
$GAuthBody = "refresh_token=$refreshToken&client_id=$ClientID&client_secret=$ClientSecret&grant_type=$grantType"
$GAuthResponse = Invoke-RestMethod -Method Post -Uri $requestUri -ContentType "application/x-www-form-urlencoded" -Body $GAuthBody
$accessToken = $GAuthResponse.access_token
$headers = #{"Authorization" = "Bearer $accessToken"
"Content-type" = "application/json"}
$spreadsheetId = "1htbeGlqZ4hojQBWl9fxE4nW_KZI9uVwi0ApzNOIbwnY"
$currentDate = (Get-Date).ToString('MM/dd/yyyy')
$currentTime = (Get-Date).ToString('HH:mm:sstt')
$json = #”
{
"range": "HIL_APP!A1:G1",
"majorDimension": "ROWS",
"values":
[[
"HIL_NAME",
"$env:ComputerName",
"$currentDate",
"$currentTime",
"$env:UserName",
"input from user",
"attempt"
],]
}
“#
$write = Invoke-WebRequest -Uri "https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/HIL_APP!A1:G1:append?valueInputOption=USER_ENTERED" -Method Post -ContentType "application/json" -Body $json -Headers #{"Authorization"="Bearer $accessToken"}
$read = Invoke-WebRequest -Uri "https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/HIL_APP!A1:G1" -Headers #{"Authorization"="Bearer $accessToken"}
$read
Write-Output "read: " ($read.Content | ConvertFrom-Json)
$scriptId = "1eF7ZaHH-pw2-AjnRVhOgnDxBUpfr0wALk1dVFg7B220bg_KuwVudbALh"
$json = #"
{
"function": "fromPS",
"parameters": ["myparam"],
"devMode": true
}
"#
$resp = Invoke-WebRequest -Uri "https://script.googleapis.com/v1/scripts/${scriptId}:run" -Method Post -ContentType "application/json" -Body $json -Headers #{"Authorization"="Bearer $accessToken"}
$resp
Write-Output "script response: " ($resp.Content | ConvertFrom-Json)
}
$error.Clear()
clear
doit
In order to run the function of Google Apps Script (GAS) using Apps Script API, it is required to do a bit complicated settings. In this case, I would like to propose for testing to run the GAS function as follows. This flow might be too careful.
Flow:
Link the Cloud Platform Project to Google Apps Script Project. Ref
Install for running the GAS function with the scripts.run method in Apps Script API. Ref
Put the script you want to run to the script editor of Google Apps Script.
Here, please run the function by the script editor and confirm whether the script works. By this, the issue of the script can be avoided.
Put the following script for testing to run. This is used for 1st test of Apps Script API.
function test() {
return "ok";
}
Put a following sample script for retrieving the access token. This is used for testing it. Please run this at the script editor, and copy the returned access token.
function getToken() {
Logger.log(ScriptApp.getOAuthToken());
}
Test to run the GAS function of test() using the retrieved access token. In this case, the script of powershell is used by replacing $accessToken = $GAuthResponse.access_token.
When an error occurs, please confirm the settings of Apps Script API. In this case, it can be said that the GAS script is correct.
When no error occurs, please test to run the function you want to run. In this case, the required scopes have already been included in the access token. By this, the issue of scopes can be avoided.
When above test is done and your script for using Apps Script API works, please retrieve the refresh token using the scopes. The scopes can be seen at the script editor. By this, the valid access token can be retrieved by the refresh token. And your script can be used at the local PC.
References:
Linking Cloud Platform Project to Google Apps Script Project
Executing Functions using the Apps Script API
Related
I have a need to make a few historical data pulls via REST API call using Powershell. I'm stuck with one of the endpoints where the data volume is over 4 GB. When I run the Powershell script in the Powershell ISE it works as expected. But, When I run the same via SQL Server Integration Services Execute Process Task it's not able to download the JSON payload.
Is there a better way to tackle this? Are there any limitations one should be mindful of?
$Header = #{
"authorization" = "Bearer $token"
}
#make REST API call
$Parameters = #{
Method = "GET"
Uri = "https://api.mysite.com/v1/data"
Headers = $Header
ContentType = "application/json"
Body = $BodyJson
}
Invoke-RestMethod #Parameters
Error: System.OutOfMemoryException
When using Azure Devops functions such as creating a new Repo or starting a pipeline is there any way to authenticate the user without an Access token through Powershell? The only other solution that I found is Azure CLI though I would prefer to Invoke the web API calls.
Actually, indeed you can auth the Azure DevOps REST API without using a PAT(personal access token), but you could not auth it without any access token. Even if you use the user account to auth, essentially it will generate an access token to auth.
For your requirement, if you want to use powershell to auth the REST API, you could use the script below.
Make sure you have installed the Az powershell module, and login with a user account which has the permission in your devops org via Connect-AzAccount.
Here is a sample to start the pipeline with Runs - Run Pipeline. This sample uses the Azure AD access token to auth, please note don't change the 499b84ac-1321-427f-aa17-267ca6975798 in the script, it is the well-known resource id of the DevOps REST API, it works for me.
$token = (Get-AzAccessToken -ResourceUrl "499b84ac-1321-427f-aa17-267ca6975798").Token
$URL = 'https://dev.azure.com/orgname/testpro1/_apis/pipelines/52/runs?api-version=6.0-preview.1'
$header = #{
'Authorization' = 'Bearer ' + $token
'Content-Type' = 'application/json'
}
$body = #"
{
"resources": {
"repositories": {
"self": {
"refName": "refs/heads/main"
}
}
}
}
"#
Invoke-RestMethod -Method Post -Uri $URL -Headers $header -Body $body | ConvertTo-Json
Requirements
My requirement is that for my Azure devops release pipeline I want to tag a specific commit with an annotated tag which contains the build number and the date (which is auto-set on an annotated tag).
Proposed solution
My solution to this is to use a the Azure Powershell pipeline task, the one shown here:
The task (ignore what's in the script box right now) will use the Azure Subscription that I have set in order to authenticate towards the Azure DevOps REST API. I have successfully been able to perform the task I want using a personal access token (PAT) but this is not stable long-term for a whole team and I want to use our Azure Subscription.
The problem
My problem is that I'm not sure how to use the authentication of the Azure Subscription correctly. I seem to get some data using Get-AzureRmContext (see current code below) and then I found a GitHub issue which seems to do sort of the same thing. The code gets some kind of OAuth token but using the code below, Azure still returns to me that I need to sign in, so I assume it's not the correct token. I don't understand how things hatch into each other.
Note that my subscription should have all the permissions it needs to do what I want.
Code so far:
Function Get-AccessToken($tenantId) {
$cache = [Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache]::DefaultShared
$cacheItem = $cache.ReadItems() | Where-Object { $_.TenantId -eq $tenantId } | Select-Object -First 1
return $cacheItem.AccessToken
}
$context = Get-AzureRmContext
$uri = "https://dev.azure.com/<my_org>/<my_area>/_apis/git/repositories/<project_sha>/annotatedtags?api-version=5.0-preview.1"
$token = Get-AccessToken $context.tenantID
$body = #"
{
"taggedObject": {
"objectId": "$(BUILD.SOURCEVERSION)"
},
"name": "D-$(Build.BuildNumber)",
"message": "dummy"
}
"#
$header = #{"Authorization" = "Bearer" + $token}
Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Body $body -Headers $header
Any help is greatly appreciated!
There is the example for the build tasks: Use a PowerShell script to customize your build pipeline
You have to enable access to token (option Allow Scripts to Access OAuth Token)
Then use it in your script. Script from the example:
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/definitions/$($env:SYSTEM_DEFINITIONID)?api-version=5.0"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
I have VSTS builds that use the Powershell script to access the VSTS API, similar to that detailed in Microsoft's Documentation.
The document states:
To enable your script to use the build process OAuth token, go to the Options tab of the build definition and select Allow Scripts to Access OAuth Token.
After you've done that, your script can use to SYSTEM_ACCESSTOKEN
environment variable to access the VSTS REST API. For example:
Example:
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build-release/definitions/$($env:SYSTEM_DEFINITIONID)?api-version=2.0"
Write-Host "URL: $url"
$definition = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Definition = $($definition | ConvertTo-Json -Depth 1000)"
As detailed in Microsofts Documentation, I'm sure you used to go to Build > Options and click 'Allow Scripts to Access OAuth Token', but it is no longer there (see pic below).
When I try a build I get the following (which doesn't happen for my old builds):
Invoke-RestMethod :
{"$id":"1","innerException":null,"message":"TF400813: The user '' is
not authorized to access this
In addition, when I clone a build (which worked nicely when I did it 3 months ago), the property is set to false (it's set to true on the original).
UPDATE: If I export from VSTS, change that property and import again, it works, but I really need a solution without this sort of manual intervention.
How should this be done now please?
It is available in the agent phase now
I generated an server key for Chrome Store API in the Developer Dashboard. I would like to publish a .zip file containing my extension programmatically. The instructions in https://developer.chrome.com/webstore/using_webstore_api show OAuth, Bearer token authentication. How can I use the server key instead?
Things I tried: header "X-ApiKey" = "$apiKey", adding ?key=$apiKey, etc.
In all cases
{"error":{"errors":[{"domain":"global","reason":"required","message":"Login
Required","locationType":"header","location":"Authorization"}],"code":401,"message":"Login
Required"}}
For this example I have been using Powershell Invoke-RestMethod
$headers = #{
"X-ApiKey" = $apiKey
"X-Goog-Api-Version" = "2"
}
$endpoint = "https://www.googleapis.com/upload/chromewebstore/v1.1/items/$appId/?key=$apiKey"
Write-Host $endpoint
$response = Invoke-RestMethod $endpoint -Method Put -InFile $filePath -Headers $headers
More docs, and no clues - https://developer.chrome.com/webstore/api_index
You can't. API keys are only used to access public data. To use the Chrome Store API, you must authenticate as the user who you wish to publish the app as and, thus, you must supply an OAuth token. Check out the OAuth 2.0 Playground for an example of how to get an OAuth token.