Use Powershell to upload to Bitbucket Downloads section - powershell

So we switched to Bitbucket recently - Love the different pricing model / the branch and repo permissions. But, I REALLY miss the Releases feature in GitHub.
BB does however have a "Downloads" section that we can upload recent binaries to. But... It isnt exposed via their API.
I found a nifty script that uses cURL, but I wanted to do this in PowerShell so I dont need any special programs (we use AppVeyor as our CI Server, no cURL).
I have this mostly working - The process is:
Load Signin page to get CSRF token - working
Sign in, redirecting to downloads page - working
Upload file - failing
My code is here
I have isolated the problem to the form data. Here is what it looks like in fiddler when I just do the upload myself:
But when I use Powershell I cannot get it to populate the "WebForms" tab of the request. I've tried using the -InFile and specifying the file to upload, but Bitbucket requires the other shown parameters as well.
How do I specify a series of "Form Fields" to include in the request with Powershell?
EDIT
Adding code here, even though it makes this messy.
$baseUri = "https://bitbucket.org"
$teamName = "xxxxxxxxx"
$projectName = "xxxxxxxxxxxxxxx"
$page = "/$teamName/$projectName/downloads"
$uri = "https://bitbucket.org/account/signin/"
$username = "xxxxxxxxxxxxxxxx"
$password = "xxxxxxxxxxxxxxxx"
$headers = #{
"referer" = "$uri"
}
$json = #"
{
"username":"$username",
"password":"$password",
"submit":"",
"next":"$page",
"csrfmiddlewaretoken":""
}
"#
$formData = #"
{
"token":"",
"csrfmiddlewaretoken":""
}
"#
$body = $json | ConvertFrom-Json
$formData2 = $formData | ConvertFrom-Json
#Load the page once to get the csrf token
Invoke-RestMethod -Uri $uri -SessionVariable mySession -Method Get -OutFile test2.html
#Parse the token
$body.csrfmiddlewaretoken = $mySession.Cookies.GetCookies("https://bitbucket.org")[0].Value
$formData2.csrfmiddlewaretoken = $mySession.Cookies.GetCookies("https://bitbucket.org")[0].Value
#Load the token into the object
$json = $body | ConvertTo-Json
$formData = $formData2 | ConvertTo-Json
#build the uri data needed by bb
$uriData = "username=" + $body.username + "&password=" + $body.password + "&submit=&next=" + $body.next + "&csrfmiddlewaretoken=" + $body.csrfmiddlewaretoken
#Sign into BB now
Invoke-RestMethod -Uri "https://bitbucket.org/account/signin/" -WebSession $mySession -Body $uriData -Method Post -OutFile test.html -Headers $headers
#Update referer to the downloads page
$headers.referer = $baseuri + $page
$fulluri = $baseuri + $page
#Upload the file
Invoke-RestMethod -Uri "$fulluri" -Method Post -OutFile test3.html -WebSession $mySession -Headers $headers -Body $formData -ContentType "multipart/form-data"

Related

Extract releases from azure DevOps projects organization

I have an Azure DevOps organization with more 300 project and I want to extract release from the org for all DevOps project. I have tried using below PowerShell script but it is just giving 100 record at a time. and also it is saying that extracted json file is not in valid format.
Here is my PowerShell script.
$token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
$url = "https://dev.azure.com/{orgnization}/_apis/projects?api-version=6.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token" } -Method Get -ContentType application/json
Foreach ($projectName in $response.value.name) {
$url1 = "https://vsrm.dev.azure.com/{orgnization}/$($projectname)/_apis/release/releases?api-version=6.0"
$response = Invoke-RestMethod -Uri $url1 -Headers #{Authorization = "Basic $token" } -Method Get -ContentType application/json-patch
echo $response | ConvertTo-Json -Depth 99 | Out-File "D:\\file.json" -Append
}
I tried adding $top parameter with first API call which works fine if I am trying in browser but in PowerShell it is not working.
https://dev.azure.com/uniperteamservices/_apis/projects?api-version=6.0&$top=500
How can I accomplish my below two requirement?
How can extract all record, not just 100
Why extracted json file is showing as invalid format when I am converting to excel?
If you can modify above PowerShell script for my requirement, it will be appreciated.
Thanks
Step through your code in a debugger.
$top wrapped in double quotes will try to interpolate a variable named $top. You need to escape the $ with a ` character. i.e.
`$top

OneDrive FB create Folder with Microsoft Graph API Powershell

I just want to create a folder one my OneDrive for Buiness Account through the Graph API. After many hours I got stuck with an error which I really can't comprehend. It says that the property 'Attributes' does not exist on type 'oneDrive.folder' and I should not use this property. The problem is that I don't use this property. After alot of research I think it has something to do with the pinned metadata or something like that. But in gerneral I really dont know what to do futher.
I used the Graph Explorer and another website to create this script.
The Error:
-1, Microsoft.SharePoint.Client.InvalidClientQueryException
The property 'Attributes' does not exist on type 'oneDrive.folder'.
Make sure to only use property names that are defined by the type.
And this is my code:
$clientId = "XXXXXXXXXXXXXX"
$tenantId = "XXXXXX.onmicrosoft.com"
$clientSecret = 'XXXXXXXXXXXX'
$uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
$body = #{
client_id = $clientId
scope = "https://graph.microsoft.com/.default"
client_secret = $clientSecret
grant_type = "client_credentials"
}
$tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing
$token = ($tokenRequest.Content | ConvertFrom-Json).access_token
Write-Host $token
$uri = "https://graph.microsoft.com/v1.0/<ID XXXXXXX>/drive/root/children"
$method = 'POST'
$head= #{Authorization = "Bearer $token"}
$postPara= #{
name= "NewFolder"
folder= {}
} | ConvertTo-Json
$antwort = Invoke-RestMethod -Headers $head -Uri $uri -Method $method -Body $postPara -ContentType "application/json"
Write-Host $antwort
It really should work and I'm sitting on this sample task for over 10 Hours ._.
The issue with you code is
$postPara= #{
name= "NewFolder"
folder = {}
} | ConvertTo-Json
If you just output $postPara you will see the issue is because your missing the # in front of value in folder you will actually get the details from the underlying script populated in there. so try
$postPara= #{
name= "NewFolder"
folder = #{}
} | ConvertTo-Json
$postPara
Which should fix it.A good diag tool is also to use fiddler to look at the request being sent to server.

REST API failure: Invoke-WebRequest : 404

The Powershell code bellow writes and reads values to Google Sheets (works fine) and should run the function myfunction in an Apps Script project using API, but Invoke-WebRequest returns the error bellow:
Invoke-WebRequest : 404. That’s an error. The requested URL /v1/scripts/=ya29.a0Ae4lvC3k8aahOCPBgf-tRf4SRFxdcCE97fkbXLAJqZ4zRCLnBp9prwEcBYBAf
lYP6zyW3fLeD3u4iSw5jYtDAdgZiSsTjzQbCpj9e_ahCA0xwC_1NBTjYkPwqFdLli7LNpfFcuedFDhdUpfnKTRZdbBWIf2ZyxyuGc6p was not found on this server. That’s
all we know.
No C:\Users\F76254C\Desktop\Nova pasta\Batch files\Available Projects\Latam HIL Lab Menu\libs\Google\WriteToGoogleSheets.ps1:64 caractere:13
+ $resp = Invoke-WebRequest -Uri "https://script.googleapis.com/v1/ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
I am not sure if the JSON representation of request body is set correctly or if the error was caused for something else.
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"}
$DocumentID = "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/$DocumentID/values/HIL_APP!A1:G1:append?valueInputOption=USER_ENTERED&access_token=$($accessToken)" -Method Post -ContentType "application/json" -Body $json
$read = Invoke-WebRequest -Uri "https://sheets.googleapis.com/v4/spreadsheets/$DocumentID/values/HIL_APP!A1:G1?access_token=$($accessToken)"
Write-Output "Response: " ($read.Content | ConvertFrom-Json)
$scriptId = "1eF7ZaHH-pw2-AjnRVhOgnDxBUpfr0wALk1dVFg7B220bg_KuwVudbALh"
$json = #”
{
"function": "myfunction",
"parameters": [
"attempt" string
],
"devMode": true
}
“#
$resp = Invoke-WebRequest -Uri "https://script.googleapis.com/v1/scripts/$scriptId:run?access_token=$($accessToken)" -Method Post -ContentType "application/json" -Body $json
# Write-Output "Response: " ($resp.Content | ConvertFrom-Json)
}
clear
doit
EDIT:
Google App Script code:
function toSpreadsheet(text2write)
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("HIL_APP");
for (var i = 1; i < sheet.getLastRow(); i++)
{
sheet.getRange(i+1, 8, 1).setValue(text2write)
}
return "myreturn"
}
function myfunction(params)
{
toSpreadsheet(params)
}
You could confirm that the script for writing and reading values for Google Sheets worked fine.
You want to modify only the script for running the Google Apps Script using Apps Script API.
You have already been able to use Apps Script API.
Your access token can be used for running the Google Apps Script.
You want to achieve this using Invoke-WebRequest of powershell.
Modification points:
From your error message and your script, I would like to propose the following modification points.
From "https://script.googleapis.com/v1/scripts/$scriptId:run?access_token=$($accessToken)" to "https://script.googleapis.com/v1/scripts/${scriptId}:run"
In your script, the endpoint is https://script.googleapis.com/v1/scripts/. This is incomplete endpoint.
I think that the reason of your current error message is due to this.
Please use the access token at the request header instead of the query parameter. Ref
I think that this can be also said for using Sheets API.
I think that "attempt" string is "attempt".
Please modify ” to ".
Modified script:
When the request to Apps Script API in your script is modified, it becomes as follows.
$scriptId = "1eF7ZaHH-pw2-AjnRVhOgnDxBUpfr0wALk1dVFg7B220bg_KuwVudbALh"
$json = #"
{
"function": "myfunction",
"parameters": ["attempt"],
"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}"}
Note:
In my environment, I could confirm that above modified script worked. Unfortunately, I cannot understand about your flow for setting to run the Google Apps Script with Apps Script API. So if in your environment, an error occurs, please confirm the settings for running the script with Apps Script API, again.
I think that "Bearer ${accessToken}" can be also modified to "Bearer $accessToken".
Reference:
Executing Functions using the Apps Script API

Powershell API Data Extraction

I'm getting data back from an API for a system of ours using Powershell but it doesn't quite return it correctly. It is putting the data all under one header as seen below. I'm trying to extract the downloadLink part only
Tried converting to JSON to see if I could get anywhere else with it.
$token = ".."
$web = Invoke-RestMethod -uri $url -Method Get -Headers #{'Authorization' = $token}
echo $web
I get this as the outcome:
documents
---------
{#{documentName=Name.docx.pdf; downloadLink=https://app.xxx.com/api/docs/employees/111/shared/111}, {#{documentName=Name.docx.pdf; downloadLink=https://app.xxx.com/api/docs/employees/111/shared/111} ...
What I need to get is the downloadLink, but as it's all coming under the documents header I can't do a simple select or get on it.
Have you tried converting the results from JSON using ConvertFrom-Json? See the code example below.
Please note the change I made to the ContentType to the Invoke-RestMethod as well.
$token = ".."
$web = Invoke-RestMethod -uri $url -Method Get -ContentType "application/json" -Headers #{'Authorization' = $token}
$webResults = $web | ConvertFrom-Json
echo ($json | ConvertFrom-Json).downloadLink

How to attach CSV file to Service Now incident via REST API using PowerShell?

I need to attach the file either xlsx or CSV to a particular incident via SNOW REST API using PowerShell script. I have tried with the below code:
if (!$script:ServiceNowCreds) {
$script:ServiceNowCreds = Get-Credential
}
$snow_url = 'https://dev652xx.service-now.com/api/now/table/incident'
$Body = #{
'number' = 'INC00xx059'
}
$result = Invoke-RestMethod -Uri $snow_url -Credential $script:ServiceNowCreds -Body $Body -ContentType "application/json"
$result.result | select sys_id, number | ForEach-Object {
$Upload_snow_url ='https://dev652xx.servicenow.com/api/now/attachment/upload'
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Content-Type','text/csv')
$headers.Add('Accept','*/*')
$sys_id = $_.sys_id
$incident_number = $_.number
$UploadBody = #{
'table_name'='incident';
'table_sys_id'=$sys_id;
'file_name' = 'C:\Users\suganthanraj.p\Documents\Servers.csv'
}
$uploadParam = $UploadBody | ConvertTo-JSon
Write-Host $sys_id
Write-Host $incident_number
$UploadResult = Invoke-RestMethod -Uri $Upload_snow_url -Credential $script:ServiceNowCreds -Body $uploadParam -Method Post -Headers $headers
$UploadResult
}
When I execute the above script I am getting the below error:
Invoke-RestMethod : The remote server returned an error: (415) Unsupported
Media Type.
At C:\Users\suganthanraj.p\Desktop\SNOW-UploadAttachment.ps1:39 char:21
+ ... oadResult = Invoke-RestMethod -Uri $Upload_snow_url -Credential $scr ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Try changing you content type to "multipart/form-data"
$headers.Add('Content-Type','multipart/form-data')
$UploadBody = #{
'table_name'='incident';
'record_sys_id'=$sys_id;
'uploadFile' = 'C:\Users\suganthanraj.p\Documents\Servers.csv'
}
The error says "The remote server returned an error: (415) Unsupported
Media Type."
Doco on the api can be found here:
https://docs.servicenow.com/bundle/geneva-servicenow-platform/page/integrate/inbound_rest/reference/r_AttachmentAPI-POSTmultipart.html
Your best option would be leverage the OOB Attachment API in ServiceNow. You will need to make a post call from powershell. Powershell has two options for this Invoke-RestMethod and Invoke-WebRequest. I have had better luck with the latter when trying to POST. You might also first build your rest call in Postman make sure you can get the attachment into ServiceNow, then worry about writing your PS.
$Body = #{
User = 'jdoe'
password = 'P#S$w0rd!'
}
$LoginResponse = Invoke-WebRequest 'http://www.contoso.com/login/' - SessionVariable 'Session' -Body $Body -Method 'POST'
$Session
$ProfileResponse = Invoke-WebRequest 'http://www.contoso.com/profile/' -`WebSession $Session $ProfileResponse`
Finally i found answer from the below link
https://community.servicenow.com/community?id=community_question&sys_id=d3707023dbaceb8023f4a345ca961949 and below is the code:
# Eg. User name="admin", Password="admin" for this code sample.
$user = "admin"
$pass = "XXX"
# Build auth header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $pass)))
# Set proper headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization',('Basic {0}' -f $base64AuthInfo))
$headers.Add('Accept','application/json')
$headers.Add('Content-Type','application/json')
# Specify endpoint uri
$uri = "https://dev652XX.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=850XXXXX2200e0ef563dbb9a71c1&file_name=TreeSizeReport.csv"
# Specifiy file to attach
$fileToAttach = "C:\Users\suganthanraj.p\Desktop\TreeSizeReport.csv"
# Specify HTTP method (POST, PATCH, PUT)
$method = "POST"
# Send HTTP request
$response = Invoke-WebRequest -Headers $headers -Method $method -Uri $uri -InFile $fileToAttach
# Print response
$response.RawContent