http requests with powershell - powershell

I am looking to make http requests to web pages with powershell, is this possible and if so, how may I achieve this?
Can I make requests to https pages? I am able to make http requests with a bat file but not https, was hoping I could https page requests with powershell.

You can use the usual WebRequest and HttpWebRequest classes provided by the .NET framework.
$request = [System.Net.WebRequest]::Create('http://example.com')
# do something with $request
It's no different from using the same classes and APIs from C#, except for the syntactic differences to PowerShell.
PowerShell v3 also brings Invoke-WebRequest and a few others.

Try this:
(New-Object System.Net.WebClient).DownloadString("http://stackoverflow.com")
WebClient.DownloadString Method (String)
or in PowerShell 3.0,
(Invoke-WebRequest http://stackoverflow.com).content
Invoke-WebRequest

Depending on what you are doing, you can also use System.Net.WebClient, which is a simplified abstraction of HttpWebRequest
$client = new-object system.net.webclient
Look here for difference: What difference is there between WebClient and HTTPWebRequest classes in .NET?
PS: With Powershell v3.0, you have Invoke-WebRequest and Invoke-RestMethod cmdlets which can be used for similar purposes

If all else fails, use Curl from http://curl.haxx.se . You can set everything, including certificate handling, POSTs, etc. Not subtle, but it works and handles all of the odder cases; e.g. you can set the --insecure flag to ignore certificate name issues, expiration, or test status.

You can create HTTP, HTTPS, FTP and FILE requests using Invoke-WebRequest cmdlet. This is pretty easy and gives many options to play around.
Example: To make simple http/https requests to google.com
Invoke-WebRequest -Uri "http://google.com"
More references can be found MSDN

This code works with both ASCII & binary files over https in powershell:
# Add the necessary .NET assembly
Add-Type -AssemblyName System.Net.Http
# Create the HttpClient object
$client = New-Object -TypeName System.Net.Http.Httpclient
# Get the web content.
$task = $client.GetByteArrayAsync("https://stackoverflow.com/questions/7715695/http-requests-with-powershell")
# Wait for the async call to finish
$task.wait();
# Write to file
[io.file]::WriteAllBytes('test.html',$task.result)
Tested on Powershell 5.1.17134.1, Win 10

Try this PowerShell module: https://github.com/toolkitx/simple-request
Install by Install-Module -Name SimpleRequest
Then you can send requests like
$Data = #{
"TokenUrl" = 111
"ClientSecret" = "222"
"ClientId" = "333"
"AuthResource" = "444"
"Username" = "User1"
"Password" = "Password"
"Id" = 99
"Price" = 0.99
"Value" = "Content"
}
$Sample = '
POST https://httpbin.org/post?id={{Id}}
Content-Type: application/json
Authorization: Bearer {{QIBToken}}
{
"id": {{Id}},
"value": "{{Value}}"
}'
$Response = Invoke-SimpleRequest -Syntax $Sample -Context $Data
Please refer to GitHub for detail introductions

This method downloads the content:
# PowerShell 2 version
$WebRequest=New-Object System.Net.WebClient
$WebRequest.UseDefaultCredentials=$true
#$WebRequest.Credentials=(Get-Credential)
$Data=$WebRequest.DownloadData("http://<url>")
[System.IO.File]::WriteAllBytes("<full path of file>",$Data)
# PowerShell 5 version
Invoke-WebRequest -Uri "http://<url>" -OutFile "<full path of file>" -UseDefaultCredentials -ContentType

Related

REST API: adapt a cURL POST to Powershell 5 (upload files)

I have this cURL command that I must adapt to Powershell in order to upload different files. In order to do that, I have mandatory fields that I need use in the request.
I've tried like a dozen of different scripts, nothing works.
Can someone help me out with this?
It should be plain simple, but I am missing something.
cURL command:
curl -H "Authorization: Bearer xxx"
-F "parentDirectoryId=1"
-F "name=AutoUpload"
-F "contents=#C:\temp\test.pdf"
https://url/v1/api/files?
This is going to depend on which version of Powershell you are using. If you have Powershell 6 you can use the simple method below which uses the form parameter. If you use another version you can use the more complicated example #4 which is outlined on the Microsoft Docs:
$Uri = 'https://url/v1/api/files?'
$Form = #{
parentDirectoryId= '1'
name = 'AutoUpload'
contents= Get-Item -Path 'C:\temp\test.pdf'
}
$token = ConvertTo-SecureString "xxx" -AsPlainText -Force
$Result = Invoke-RestMethod -Uri $Uri -Method Post -Form $Form -Authentication Bearer -Token $token
This example uses the new Authentication and Form parameters in Invoke-RestMethod. Depending on your Authentication type, you will need either a Token or Credentials parameter with additional information. The Form parameter simplifies what was previously a complicated process for adjusting the body or URI per request.

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.

Invoke-WebRequest doesn't work until I call WebClient.DownloadString

I'm using powershell v5 to call an internal API using TLS1.2 with a self-signed cert. When I call the api I always get Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send.
E.g.:
PS> [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
PS> [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
PS> $url = "https://someinternalserver/blah"
PS> $response = Invoke-WebRequest $url
Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send.
At line:1 char:1
(I've looked in the error object but I don't see anything helpful.)
However if I call the same URL using an instance of WebClient, then the call using WebClient AND all subsequent powershell calls works fine:
PS> $webClient = New-Object System.Net.WebClient
PS> $str = $webClient.DownloadString($url)
PS> Write-Host $str
body of request
PS> $response = Invoke-WebRequest $url
PS> Write-Host $response.Content
body or request
I'm not sure what's going on, but I suspect it has something to do with the self-signed cert, or the crypto. Here's what chrome says about the crypto:
I've used powershell to call APIs with self-signed certs before but never had these kind of issues.
Resolution: I'd like to call the API without first using WebClient.
Thanks.
So dug into the error more and found this in an inner exception:
There is no Runspace available to run scripts in this thread.
You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type.
The script block you attempted to invoke was: $true
Which led me here:
Powershell 3.0 Invoke-WebRequest HTTPS Fails on All Requests
Which led me here:
https://stackoverflow.com/a/15841856/6311875
Using that code instead of the {$true} did the trick.
So, this further reinforces the idea that all questions are already answered on SO, you just have to look hard enough.

POSTing data to ServiceNow via Powershell using Invoke-WebRequest

I am trying to POST information into a table in ServiceNow via a Powershell script. When I run it I get an error
Invoke-WebRequest : The remote server returned an error: (500) Internal Server Error.
Can someone help me figure out how to solve this? Thank you all in advance.
$userName = 'helpMe'
$password = 'iAmStuck' | ConvertTo-SecureString -asPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($userName, $password)
$uri = 'stuff'
$postParams = "test"
#[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
Invoke-WebRequest -Uri $uri -Method Post -Body $postParams -Credential $cred
ServiceNow has a REST API explorer with various code examples to start working with.
Below is an example that I threw together that posts to the incident table with an admin account. Two important factors here, the user must have roles (here for info https://docs.servicenow.com/bundle/istanbul-servicenow-platform/page/integrate/inbound-rest/reference/r_RESTAPIRoles.html) to use the API and must have access to the table you are trying to post to. Also, note that the body of the post needs to be RAW JSON and all the correct header data is supplied in the URL. If successful ServiceNow will return JSON data about the post.
# Eg. User name="admin", Password="admin" for this code sample.
$user = "admin"
$pass = "noPassword"
# 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://xxxxx.service-now.com/api/now/table/incident"
# Specify HTTP method
$method = "post"
# Specify request body
{request.body ? "$body = \"" :""}}{\"active\":\"true\",\"number\":\"123\",\"short_description\":\"test\"}"
# Send HTTP request
$response = Invoke-WebRequest -Headers $headers -Method $method -Uri $uri -Body $body
# Print response
$response.RawContent
Even though you posted code, you posted nothing relevant to the problem. Whatever ServiceNow is might have an API for reference on what it's expecting. Often when interacting with web-based APIs, there is a structure that is required for the API to be able to understand the data you're supplying in $postParams. Sometimes it can just be key->value pairs in the case of a flat HTTP POST but often times for RESTful APIs you'll need to structure a JSON header as defined by the API documentation.
If you do a search for "servicenow powershell interaction" it looks like there's a GitHub project for interacting with ServiceNow via PowerShell and also a PDF that specifcally covers this topic.

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.