Unable to upload zip on azure using PowerShell through Jenkins - powershell

I am trying to auto deploy build on azure. For this i use powershell script to upload zip on azure. There is two part of the script -> First to clean the wwwroot folder and second part is to upload zip to wwwroot. It runs successfully when i run script through Powershell exe but gives error when run through Jenkins. Strange thing is, it successfully runs first part but gives error on second part.
Powershell Script :
$username = "`$347testpass"
$password = "xyz"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password)))
$userAgent = "powershell/1.0"
#Clean wwwroot folder
$apiUrl1 = "https://347testpass.scm.azurewebsites.net/api/command"
$commandBody = #{
command = "rmdir D:\home\site\wwwroot /Q /S"
}
Invoke-RestMethod -Uri $apiUrl1 -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST ` -ContentType "application/json" -Body (ConvertTo-Json $commandBody) | Out-Null
#Upload zip file
$apiUrl = "https://347testpass.scm.azurewebsites.net/api/zip/site/wwwroot/"
$filePath = "D:\AzureWeb\Upload\qwerty.zip"
Invoke-RestMethod -Uri $apiUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -UserAgent $userAgent -Method PUT -InFile $filePath -ContentType "multipart/form-data"
Error display in Jenkins Console :
Invoke-RestMethod : The request was aborted: The request was canceled.
At C:\Users\Harsh.Sharma\AppData\Local\Temp\hudson8158442147919891501.ps1:34 
char:1
+ Invoke-RestMethod -Uri $apiUrl -Headers #{Authorization=("Basic {0}" -f 
$base64A ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~
    + CategoryInfo : NotSpecified: (:) [Invoke-RestMethod], WebExcept 
   ion
    + FullyQualifiedErrorId : System.Net.WebException,Microsoft.PowerShell.Com 
   mands.InvokeRestMethodCommand

Finally it works after added couple of thing like timeout, change Method type, security protocol tls12.
$apiUrl = "https://347testpass.scm.azurewebsites.net/api/zipdeploy"
$filePath = "C:\BuildDeploymentAzureEnterprise3.4\Unzipped\AzureBuildFiles.zip"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-RestMethod -Uri $apiUrl -DisableKeepAlive -TimeoutSec 1000 -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -UserAgent $userAgent -Method POST -InFile $filePath -ContentType "multipart/form-data"

Try using -DisableKeepAlive with Invoke-RestMethod.

Related

Invoke-RestMethod from PowerShellScript doesn't work but work from commandline

I am trying to invoke a rest method from powershell script to get git changes from azure repo. When i run the whole process one by one command it works but when i try to run the whole script by writing a powershell script it doesn't work as expected giving empty output. can anyone tell what could be the problem here
$url = "https://dev.azure.com/<Org_Name>/<Project_Name>/_apis/git/repositories/<RepoID>/commits/$(Build.SourceVersion)/changes?api-version=5.1"
$userName = "Username"
$password = "<PAT>"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $userName,$password)))
$result = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $base64AuthInfo"} -Method GET
Write-Host $result
$changesFolders = $result.changes | Where-Object {$_.item.gitObjectType -eq "tree"} | Select-Object -Property{$_.item.Path}
foreach($path in $changesFolders)
{
Write-Host $path
}
Write-Host $changesFolder
I am not sure how but i tried Invoke-webRequest instead of Invoke-RestMethod and it worked
But I had to make some changes in the header as well otherwise it was hitting the endpoint but still giving 203 status
$headers = #{
Authorization=("Basic" + [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$PAT")));
ContentType="application/json"
}
$result = Invoke-webRequest -Uri $url -Headers $header -Method GET
Write-Host $result.StatusCode
Gives result and status code 200 as expected
note: without adding a colon before password/PAT while converting to base64string will throw 203 status
The following example is working. Additionally, you can paste our resulting URL into the browser and check the answer from your org.
$user = ""
$token = "PAT"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$orgUrl = "ORG"
$teamProject = "PROJECT"
$repoName = "REPONAME"
$commitId = "COMMITID"
$restApiGetCommit = "$orgUrl/$teamProject/_apis/git/repositories/$repoName/commits/$commitId/changes?api-version=5.1"
function InvokeGetRequest ($GetUrl)
{
return Invoke-RestMethod -Uri $GetUrl -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
}
Write-Host "Url" $restApiGetCommit
$commitInfo = InvokeGetRequest $restApiGetCommit
Write-Host "Commit: " $commitInfo.changes
foreach($path in $commitInfo.changes)
{
Write-Host "Path" $path.item.path
}

Unable to deploy .zip file using Kudu api to the Azure App Service

I'm using PowerShell inline task in the release pipeline to deploy the respective zip file to the Azure App Service, but im unable to achieve it due to the below error. Can you please let me know if there is any thing that im missing here.
I'm getting below error
Invoke-RestMethod : Path 'D:\a\r1\a_CI-VI-Maven/DeployPackages/marnet.zip' resolves to a directory. Specify a path including a file name, and then retry the command.
Below is the script that im using:
$username = "username"
$password = "pwd"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password)))
$userAgent = "powershell/1.0"
$apiUrl = "https://{appservice}.scm.azurewebsites.net/api/zip/site/wwwroot/webapps/"
$filePath = "$(System.DefaultWorkingDirectory)_CI-VI-Maven/DeployPackages/marnet.zip"
Invoke-RestMethod -Uri $apiUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -UserAgent $userAgent -Method POST -InFile $filePath -ContentType "multipart/form-data"
Check your folder structure, it seems that you have a folder named marnet.zip!
Your issue occurred since the $filePath = "$(System.DefaultWorkingDirectory)_CI-VI-Maven/DeployPackages/marnet.zip" is a path to folder marnet.zip instead of a real marnet.zip file.
My reproducible steps:
1.Everything works well when my s.zip file locates directly under build artifacts folder.
2.Change something in Build pipeline to create s.zip folder, and move the s.zip file to this folder.
3.Then, same issue occurs:
Looking here
$username = "`$website"
$password = "pwd"
# Note that the $username here should look like `SomeUserName`, and **not** `SomeSite\SomeUserName`
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password)))
$userAgent = "powershell/1.0"
# Example 1: call the zip controller API (which uses PUT)
$apiUrl = "https://{sitename}.scm.azurewebsites.net/api/zip/site/wwwroot/"
$filePath = "C:\Temp\books.zip"
Invoke-RestMethod -Uri $apiUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -UserAgent $userAgent -Method PUT -InFile $filePath -ContentType "multipart/form-data"
# Example 2: call the zipdeploy API (which uses POST)
$apiUrl = "https://{sitename}.scm.azurewebsites.net/api/zipdeploy"
$filePath = "C:\Temp\books.zip"
Invoke-RestMethod -Uri $apiUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST -InFile $filePath -ContentType "multipart/form-data"
So if you want to use zip controller API please change your verb to PUT insted of POST.

What does the Body of the Invoke-RestMethod for queuing a build need to contain? [duplicate]

I have the following script
Param(
[string]$vstsAccount = "abc,
[string]$projectName = "abc",
[string]$user = "",
[string]$token = "xyz"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$verb = "POST"
$body = #"
{
"definition": {
"id": 20
}
}
"#
$uri = "https://$($vstsAccount).visualstudio.com/DefaultCollection/$($projectName)/_apis/build/builds?api-version=4.1"
$result = Invoke-RestMethod -Uri $uri -Method $verb -ContentType "application/json" -Body (ConvertTo-Json $body) -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
However I get this error
Invoke-RestMethod : {"$id":"1","innerException":null,"message":"This request expects an object in the request body, but the supplied data could not be
deserialized.","typeName":"Microsoft.TeamFoundation.Build.WebApi.RequestContentException,
So I tried to queue a build from the browser and see the payload using developer tools:
{"queue":{"id":70},"definition":{"id":20},"project":{"id":"b0e8476e-660a-4254-a100-92ef0ec255e5"},"sourceBranch":"refs/heads/master","sourceVersion":"","reason":1,"demands":[],"parameters":"{\"system.debug\":\"false\"}"}
So, I replaced that into my script:
$body = #"
{"queue":{"id":70},"definition":{"id":20},"project":{"id":"b0e8476e-660a-4254-a100-92ef0ec255e5"},"sourceBranch":"refs/heads/master","sourceVersion":"","reason":1,"demands":[],"parameters":"{\"system.debug\":\"false\"}"}
"#
However I keep getting the same error.
The official documentation for this endpoint is here, but its not clear
https://learn.microsoft.com/en-us/rest/api/vsts/build/builds/queue?view=vsts-rest-4.1#request-body
To queue a build with REST API, you can use below powershell script:
$body = '
{
"definition": {
"id": number
}
}
'
$bodyJson=$body | ConvertFrom-Json
Write-Output $bodyJson
$bodyString=$bodyJson | ConvertTo-Json -Depth 100
Write-Output $bodyString
$user="name"
$token="PAT"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$Uri = "https://account.visualstudio.com/project/_apis/build/builds?api-version=4.1"
$buildresponse = Invoke-RestMethod -Method Post -UseDefaultCredentials -ContentType application/json -Uri $Uri -Body $bodyString -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
write-host $buildresponse
This variant of Marina's answer worked for me against an on-prem TFS 2017 server:
$b= '{"buildNumber":<build id>,"definition":{"id":<build id>}}'
$user="DOMAIN\username"
$token="<PAT token>"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${user}:${token}"))
$Uri = "https://tfs.mycompany.local/<team-name>/<project-name>/_apis/build/builds?api-version=4.1"
$buildresponse = Invoke-RestMethod -Method Post -UseDefaultCredentials -ContentType application/json -Uri $Uri -Body $b -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
write-host $buildresponse
If you're running your PowerShell script on an Azure Devops Server, you can take advantage of several environment variables to automatically authenticate:
# From https://learn.microsoft.com/en-us/rest/api/azure/devops/build/builds/queue?view=azure-devops-server-rest-6.0
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/builds?api-version=6.0&definitionId=<definition_id_here>"
Write-Host "URL: $url"
# From https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/powershell?view=azure-devops-2020&tabs=yaml#example-powershell-script-access-rest-api
$pipeline = Invoke-RestMethod -Method 'Post' -Uri $url -ContentType "application/json" -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"

Issue when updating build definition using the REST api of VSTS

I want to update a variable in my build definition but when it tries to run the Invoke-RestMethod I receive the following exception:
Invoke-RestMethod : {"$id":"1","innerException":null,"message":"This request expects an object in the request body,
but the supplied data could not be
deserialized.","typeName":"Microsoft.TeamFoundation.Build.WebApi.RequestContentException,
Microsoft.TeamFoundation.Build2.WebApi, Version=14.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a","typeKey":"RequestContentException","errorCode":0,"eventId":3000}
At D:\a\_temp\231f1be5-edc0-4bd9-a2e4-efd23a8308d1.ps1:42 char:1
+ Invoke-RestMethod -Method Put -Uri "$($projectDef.Url)&api-version=2. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
eption
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Everything else seems to work, I get the build definition, I can update the variable but when I try to PUT the json back using the Invoke-RestMethod it fails.
Below is the used code which runs in a Powershell inline script:
# This script is intended to be used for PowerShell script tasks in VSTS in "inline mode"
$valueName = 'ProjectBuildNumber'
$token = 'MYTOKENCODE'
$uriRoot = $env:SYSTEM_TEAMFOUNDATIONSERVERURI
$ProjectName = $env:SYSTEM_TEAMPROJECT
$ProjectId = $env:SYSTEM_TEAMPROJECTID
$uri = "$uriRoot$ProjectName/_apis/build/definitions?api-version=2.0"
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f "", $token)))
$header = #{Authorization = ("Basic {0}" -f $base64AuthInfo)}
# Get the list of Build Definitions
$buildDefs = Invoke-RestMethod -Uri $uri -Method Get -ContentType "application/json" -Headers $header
# Find the build definition for this project
$buildDef = $buildDefs.value | Where-Object { $_.Project.id -eq $ProjectId }
if ($buildDef -eq $null)
{
Write-Error "Unable to find a build definition for Project '$ProjectName'. Check the config values and try again." -ErrorAction Stop
}
# NOTE: ensure we call the v 2.0 api! (both get and put calls need the same api versions!)
# get its details
$projectDef = Invoke-RestMethod -Uri "$($buildDef.Url)?api-version=2.0" -Method Get -ContentType "application/json" -Headers $header
if ($projectDef.variables.$valueName -eq $null)
{
Write-Error "Unable to find a variable called '$valueName' in Project $ProjectName. Please check the config and try again." -ErrorAction Stop
}
# get and increment the variable in $valueName
[int]$counter = [convert]::ToInt32($projectDef.variables.$valueName.Value, 10)
$updatedCounter = $counter + 1
Write-Host "Project Build Number for '$ProjectName' is $counter. Will be updating to $updatedCounter"
# Update the value and update VSTS
$projectDef.variables.$valueName.Value = $updatedCounter.ToString()
$projectDefJson = $projectDef | ConvertTo-Json -Depth 50 -Compress
# when we build the URL need to cater for if the Project Definition URL already has parameters or not.
$separator = "?"
if ($projectDef.Url -like '*?*')
{
$separator = "&"
}
$putUrl = "$($projectDef.Url)$($separator)api-version=2.0"
Write-Host "Updating Project Build number with URL: $putUrl"
Invoke-RestMethod -Method Put -Uri $putUrl -Headers $header -ContentType "application/json" -Body $projectDefJson | Out-Null
UPDATE
When I use postman to test this, I first run a get and then a put, it works...
Ok problem was with the character & which got replaced by \u0026. Added the following which solved this:
([System.Text.Encoding]::UTF8.GetBytes($projectDefJson))
So the last line becomes:
Invoke-RestMethod -Method Put -Uri $putUrl -Headers $header -ContentType "application/json" -Body ([System.Text.Encoding]::UTF8.GetBytes($projectDefJson)) | Out-Null

Converting Curl request to powershell

I'm trying to pass an image in power shell replicating this cURL request
curl -u user:apikey -F ‘data=#1234.jpg’
https://denton.gradesfirst.com/api/users/pictures
I authenticate fine but don't know to replicate ‘data=#1234.jpg’ in powershell so the other system will know where the picture is.
$username = "username"
$password = "apikey"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))
Invoke-RestMethod -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -uri "https://test.test.test.com/api/users/pictures" -Method Put -InFile "C:\Users\username\Downloads\pic-2017\210569.jpg" -ContentType 'image/jpg'
This is a common mis-nomer that you must use invoke-restmethod.
This should work for you. If you need to input the creds non-interactively, simply save them to a file and then pull them in to the same $cred variable - the commands remain the same.
$creds = Get-Credential
$url = "https://denton.gradesfirst.com/api/users/pictures"
Invoke-WebRequest -Credential $creds -Method Post -Uri $url -ContentType "application/x-www-form-urlencoded" -InFile "1234.jpg"