Run Powershell commands with API request, PUT request - rest

https://learn.microsoft.com/en-us/rest/api/compute/virtual-machine-run-commands/create-or-update#request-body
Could you please give an implementation example to apply the steps at the above documentation?
I couldn't figure out what are the steps and how to apply.
Thanks in advance,

I'm going at this blind since I can't use my companies Azure Environment to test but in the least this will be a good start for you to be able to troubleshoot.
I set all the requested information as variables so that you can change them as you see fit. The part that is most questionable here is how Azure wants you to do the authorization header.
On the page you linked there is an option to "Try this" on that menu you should be able to build a custom API request and it will include the headers there.
Let me know how this does and I can help troubleshoot if there are issues.
$runcommandname = ""
$subscriptionId = ""
$resourcegroupname = ""
$vmName = ""
$apiKey = ""
$resource = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourcegroupname/providers/Microsoft.Compute/virtualMachines/$vmName/runCommands/$runcommandname"
$apiversion = "?api-version=2021-07-01"
$resource = $resource + $apiversion
$authHeader = #{
'Authorization' = "apiToken $apiKey"
}
Invoke-RestMethod -Method Put -Uri $resource -H $authHeader

You can also use the Invoke-AzRestMethod cmdlet to execute the PUT operation using the existing context. Consult the reference documentation for more details: https://learn.microsoft.com/powershell/module/az.accounts/invoke-azrestmethod
Alternatively, if the goal is to run a command on a VM, you can also consider using the Invoke-AzVMRunCommand cmdlet as described here: https://learn.microsoft.com/powershell/module/az.compute/invoke-azvmruncommand.

Related

Limitations with REST API calls using Powershell

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

How to add a new dynamically discoverable capability to an agent?

Updates
I am going to propose a Capabilities Provider here as an update to my post.
If you need more details please let me know.
We currently have a bunch of shipped Capabilities Providers in the agent source code:
https://github.com/microsoft/azure-pipelines-agent/tree/master/src/Microsoft.VisualStudio.Services.Agent/Capabilities
Agent
Environment
Nix
PowerShell
What is being proposed is one additional Provider named ExecutableCapabilitiesProvider.
This new ExecutableCapabilitiesProvider will probably have a config file which can be edited on the agent machine.
The format of this file could probably be:
#name,executable
pip,pip3 freeze
xyz,/usr/bin/xyz-runner
abc,sh -C "ls -l /blah/blah"
As the maintainer of the self-hosted pool, I would configure this file with entries suiting me and have the agent run it as it starts. This way I am not hard-coding any values for my capabilities but rather those be determined at the start up.
And I would go one step further and add a new API call to add capabilities which is more flexible than the current one asking for name/values. An example, would be to change the parameters to Name, Provider, Params:
efg, NixProvider, /path/to/file/efg
klm, ExecutableCapabilitiesProvider, /usr/bin/klm -a -b -c
Original Post
I'd like to make my agents report on new capabilities which are not static but rather result of a command or something similar? How can I do that?
Our agents run on linux boxes.
To be specific, I'd like to have a new capability called pip-packages and the value for that is the result of the command pip freeze executed on the shell.
If you mean to add User-defined capabilities, then you can write a script to call the REST API to update the agent capabilities.
PUT https://dev.azure.com/{organization}/_apis/distributedtask/pools/{poolid}/agents/{agentid}/usercapabilities?api-version=5.0
Request body:
{"pip-packages": "xxxx"}
For example, you can set a variable and run command pip freeze and export the response as the value of that variable, then update the agent capability by calling the REST API:
Below PowerShell sample for your reference :
Param(
[string]$collectionurl = "https://dev.azure.com/{organization}",
[string]$poolid = "14",
[string]$agentid = "16",
[string]$user = "user",
[string]$token = "PAT/Password"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
# Run pip freeze command and get response as the value of the variable $pipfreeze (Just for your reference here, you need to extract the value with running the commands)
$pipfreeze = "response of pip freeze"
# Create json body with that value
$baseUri = "$collectionurl/_apis/distributedtask/pools/$poolid/agents/$agentid/usercapabilities?api-version=5.0"
function CreateJsonBody
{
$value = #"
{"pip-packages":"$pipfreeze"}
"#
return $value
}
$json = CreateJsonBody
# Update the Agent user capability
$agentcapability = Invoke-RestMethod -Uri $baseUri -Method Put -Body $json -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
write-host "=========================================================="
Write-host "userCapabilities :" $agentcapability.userCapabilities.'pip-packages'
write-host "=========================================================="

What is the curl equivalent command in powershell for uploading the apk file?

I am trying to perform CI/CD using Perfecto and hence I am trying to upload a file to perfecto when my Bamboo build is finished.
I was trying with the following cURL command when we have a Linux server.
curl -X POST --upload-file test.apk 'https://****.perfectomobile.com/services/repositories/media/PRIVATE:test.apk?operation=upload&user=<email>&password=<password>&overwrite=true'
Now our server is changed to Windows and hence I want a powershell script which I can use as an Inline Scripts in Bamboo.
Can you please tell me what is an equivalent script in Powershell for windows.
Many thanks in advance.
# Gather your information.
$email = "myEmail#website.com";
$password = "powershellR0cks!";
$subDomain = "****";
$url = "https://$subDomain.perfectomobile.com/services/repositories/media/PRIVATE:test.apk?operation=upload&user=$email&password=$password&overwrite=true";
$filePath = ".\test.apk";
# Make the request.
$response = Invoke-WebRequest -Uri $URL -Method Post -InFile $filePath -ContentType "application/octet-stream";
# Check for success.
if (-not ($response.StatusCode -eq 200)) {
throw "There was an error uploading the APK manifest.";
}
You may want to check the value of -ContentType, but I think that's correct. You don't necessarily need to include the scheme (HTTPS) if you don't want to, and semicolons in PowerShell are optional, but you can include them if you want.
The $response variable is an HtmlWebResponseObject that has the content of the response, the status code, and a bunch of other useful info. You can check out the available properties and methods on the object by running $response | Get-Member.
Finally, the Invoke-WebRequest cmdlet also has other parameters that may be useful to you, such as -Credential, -Headers, and more.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-5.1
As a side-note, if you run Get-Alias -Name "curl", you can see that anytime you use curl in PowerShell, you're really just calling Invoke-WebRequest. You can use the curl alias if you want, but it's generally not a good idea to use aliases in automation since they can be modified or deleted.

Install extensions when creating VSTS account with ARM template

I'm using powershell and an ARM template to create a new Team Services account + DevOps Project. Template type: microsoft.visualstudio/account
Is there a way to also install extensions via the template or powershell?
I have a couple of extensions I'm always using, It would be nice to automatically have them up and running on new projects.
thats an interesting question, if this is possible it should be mimicing this rest call.
That is most likely not possible with arm templates. Given this is not under reference on docs and the template says "operation": "link" i suppose there is no way of doing that.
If anybody stumbles upon this same problem, here's how you can do it with powershell.
After creating the VSTS account, you need to log in and create a personal access token with Extensions (read and manage) in selected scopes.
$accountName = "yourAccount"
$personalAccessToken = "your-personal-access-token"
$uri = "https://" + $accountName + ".extmgmt.visualstudio.com/_apis/extensionmanagement/installedextensionsbyname/ms-appinsights/appinsightsreleaseannotations?api-version=5.0-preview.1"
Write-Host "Installing extension: Release Annotations for Azure Application Insights"
Invoke-RestMethod `
-Method Post `
-Uri $uri `
-ContentType application/json `
-Headers #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($personalAccessToken)")) }

Powershell and NITRO API for Citrix NetScaler error on GET method

I am using a PowerShell module provided by Citrix to invoke the Nitro REST API. Calling the function I can successfully add and remove load balanced services from the load. However when I try to do a GET method to get the status of a service I get the error:
Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
I have tried running Invoke-RestMethod without using the module but get the same error
Invoke-RestMethod -WebSession $myNSSession.WebSession -Method GET -Uri https://<NetScaler IP/nitro/v1/config/service/<Service Name>
When googling this error everything seems to point to certificate issues. I had this initially even on POST method until i added the below to my script
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
So since this works for doing POST i cant see why it wouldn't for a GET!!
another weird thing is, if I put the URL directly into the browser then enter my credentials i get a response in raw text! so it looks like this is an issue with the way i am calling it in PowerShell rather than the NetScaler or the NITRO API!
Someone please help as this is driving me crazy!!
Admitedly i am new to Invoke-RestMethod commands, but try this:
$creds = Get-Credential
$service = Invoke-RestMethod -Uri https://<NetScaler IP/nitro/v1/config/service/<Service Name> -Credential $creds
What you will get is something similar to this:
*errorcode* *message* *serverity* *service*
* 0 Done NONE {#{name=<service name; n..
then type $service.service and you will see more information. whatever attributes are availible will be listed. then just follow the pattern:
$service.service.
I had the same problem with Nitro API (specifically v10.5), and found that setting certificate policies, TLS versions and trust settings had no effect. POST works, GET fails.
The solution for me was to not use the cmdlets and instead drop back to a native .Net method. Below I am still using HTTPS with an internal certificate, hence still setting the callback.
$NSProtocol = "https://"
$NSHostname = "netscaler"
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
$WebRequest = [System.Net.WebRequest]::Create("$NsProtocol$NsHostname/nitro/v1/config/hanode")
$WebRequest.Method = "GET"
$WebRequest.ContentType = "application/json; charset=utf-8";
$WebRequest.Headers.Add("AUTHORIZATION","Basic $([System.Convert]::ToBase64String([System.Text.Encoding]::GetEncoding("ISO-8859-1").GetBytes($nsuser+":"+$nspass)))")
$Response = $WebRequest.GetResponse()
$ReadStream = New-Object System.IO.StreamReader $Response.GetResponseStream()
$HaState = ConvertFrom-Json $ReadStream.ReadToEnd()
Hope that helps.