PowerShell, how to handle a page timeout from an Invoke-WebRequest? - powershell

I found that a site that I wanted to parse was down today when I went there to download a file.
The code I ran is:
$url = "https://notepad-plus-plus.org/downloads"
$page = Invoke-WebRequest -uri $url -UseBasicParsing
How can I intercept and handle this?
Is there a way to gracefully time out my request after 2 seconds if it does not get a response (which could be from the site being down or from my own internet having problems)?
What might be the best way to detect if what was returned is "connection timeout junk" as opposed to useful data that I can work with?
$url = "https://notepad-plus-plus.org/downloads" # Final url will be like: # https://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v8.4.6/npp.8.4.6.portable.x64.zip
try {
$page = Invoke-WebRequest -uri $url -UseBasicParsing -TimeoutSec 3
}
catch {
if ($_.Exception.Response.StatusCode -band 522) { "bad!"}
}

You should just call the current default error variable exception message/detail.
$url = "https://notepad-plus-plus.org/downloads"
try {$page = Invoke-WebRequest -uri $url -UseBasicParsing -TimeoutSec 3 -ErrorAction Stop}
catch {$Error[0].Exception}
# Results
<#
The operation has timed out.
#>
$url = "https://notepad-plus-plus.org/downloads"
try {$page = Invoke-WebRequest -uri $url -UseBasicParsing -ErrorAction Stop}
catch {$Error[0].Exception}
# Results
<#
The remote server returned an error: (522).
#>
Thus do what you want based on that error message.
$url = "https://notepad-plus-plus.org/downloads"
try {$page = Invoke-WebRequest -uri $url -UseBasicParsing -ErrorAction Stop}
catch
{
If (($Error[0].Exception) -match '522')
{Write-Warning -Message 'Bad stuff happened. Now, go do stuff'}
}
# Results
<#
WARNING: Bad stuff happened. Now, go do stuff
#>
Update
Timeout check.
$timer = [Diagnostics.Stopwatch]::StartNew()
$url = "https://notepad-plus-plus.org/downloads"
try {$page = Invoke-WebRequest -uri $url -UseBasicParsing -TimeoutSec 3 -ErrorAction Stop}
catch
{
$Error[0].Exception
If (($Error[0].Exception) -match 'timed out')
{Write-Warning -Message 'Timeout occurred. Do you want to set a differnet timeout'}
}
$timer.Elapsed.TotalSeconds
# Results
<#
The operation has timed out.
WARNING: Timeout occurred. Do you want to set a differnet timeout
3.0225485
#>

Related

Getting error : The underlying connection was closed: An unexpected error occurred on a send while running powershell script

$API_KEY = "xxxxxxxxxx"
# Source image files
$ImageFiles = (Get-ChildItem -Path C:\Users\sam\Desktop\jpeg\* -filter *).Name
$uploadedFiles = #()
try {
foreach ($imageFile in $ImageFiles ) {
# 1a. RETRIEVE THE PRESIGNED URL TO UPLOAD THE FILE.
# Prepare URL for `Get Presigned URL` API call
$query = "https://api.pdf.co/v1/file/upload/get-presigned-url?
contenttype=application/octet-stream&name=" + `
[IO.Path]::GetFileName($imageFile)
$query = [System.Uri]::EscapeUriString($query)
# Execute request
$jsonResponse = Invoke-RestMethod -Method Get -Headers #{ "x-api-key" = $API_KEY } -Uri
$query
if ($jsonResponse.error -eq $false) {
# Get URL to use for the file upload
$uploadUrl = $jsonResponse.presignedUrl
# Get URL of uploaded file to use with later API calls
$uploadedFileUrl = $jsonResponse.url
# 1b. UPLOAD THE FILE TO CLOUD.
$r = Invoke-WebRequest -Method Put -Headers #{ "x-api-key" = $API_KEY; "content-type"
= "application/octet-stream" } -InFile $imageFile -Uri $uploadUrl
if ($r.StatusCode -eq 200) {
# Keep uploaded file URL
$uploadedFiles += $uploadedFileUrl
}
else {
# Display request error status
Write-Host $r.StatusCode + " " + $r.StatusDescription
}
}
else {
# Display service reported error
Write-Host $jsonResponse.message
}
}
if ($uploadedFiles.length -gt 0) {
# 2. CREATE PDF DOCUMENT FROM UPLOADED IMAGE FILES
# Prepare URL for `DOC To PDF` API call
$query = "https://api.pdf.co/v1/pdf/convert/from/image"
# Prepare request body (will be auto-converted to JSON by Invoke-RestMethod)
# See documentation: https://apidocs.pdf.co
$body = #{
"name" = $(Split-Path $DestinationFile -Leaf)
"url" = $uploadedFiles -join ","
} | ConvertTo-Json
# Execute request
$response = Invoke-WebRequest -Method Post -Headers #{ "x-api-key" = $API_KEY; "Content-
Type" = "application/json" } -Body $body -Uri $query
$jsonResponse = $response.Content | ConvertFrom-Json
if ($jsonResponse.error -eq $false) {
# Get URL of generated PDF file
$resultFileUrl = $jsonResponse.url;
$DestinationFile = "C:\Users\sam\Desktop\pdf\$imagefile.split('.')[0]"
# Download PDF file
Invoke-WebRequest -Headers #{ "x-api-key" = $API_KEY } -OutFile $DestinationFile -Uri
$resultFileUrl
Write-Host "Generated PDF file saved as `"$($DestinationFile)`" file."
}
else {
# Display service reported error
Write-Host $jsonResponse.message
}
}
}
catch {
# Display request error
Write-Host $_.Exception
}
Basically this script converts bulk number of JPEG images to PDF format .Its working initially but later when i execute the script it is getting failed by this error "The underlying connection was closed: An unexpected error occurred on a send." . I googled this issue and added these two lines at the beginning of the script –
#[Net.ServicePointManager]::SecurityProtocolNet.SecurityProtocolType]::Tls12 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 .
Even after adding these two am getting the same old error .Can anyone please help me with this issue

How do I get return values from Invoke-WebRequest

I am trying to figure out how to get results from a Invoke-WebRequest to download a file from the internet. I wrote a function but it doesn't seem to get the results. StatusCode and StatusDescription never change even if it works:
function DownloadUpgradeTool()
{
##download upgrade tools from MS
Write-Host "Downloading Upgrade Tool from MS."
$url = "https://download.microsoft.com/download/3/d/c/3dcc9642-d3a0-459c-86fd-128f5a0c3cc5/Windows10Upgrade9252.exe"
$output = "c:\Temp\upgrade.exe"
$StatusCode = 1
$StatusDescription = "Error downloading file"
try
{
$response = Invoke-WebRequest -Uri $url -OutFile $output -ErrorAction Stop
}
catch
{
$StatusCode = $_.Exception.Response.StatusCode.value__
$StatusDescription = $_.Exception.Response.StatusDescription
}
Write-Host " Download Status Code: " $StatusCode
Write-Host "Download Status Description: " $StatusDescription
if ($StatusCode)
{
return $False
}
else
{
return $True
}
}
function RunUpgrade()
{
##run silent upgrade
##c:\Temp\upgrade.exe /quietinstall /skipeula /auto upgrade /copylogs c:\Temp
}
You get the status code when you evaluate the object that is returned by Invoke-WebRequest
$response = Invoke-WebRequest -URI $url -OutFile $output -ErrorAction Stop
Write-Host $response.StatusCode
$r = Invoke-WebRequest -URI https://stackoverflow.com/questions/20259251/
Write-Host $r.StatusCode
https://davidhamann.de/2019/04/12/powershell-invoke-webrequest-by-example/
Powershell implements the OOP (object-oriented programming) design paradigms and semantics i.e. when writing object-oriented code each class has to have a constructor (new()) and a destructor and it should have get() and set() methods to access (read and write) the fields (or attributes) of a class. In ps this is straighlty implemented
Return values of cmdlets are often objects (in the sense of OOP) and you can access the fields of the objects to gather the data ...
It is also possible to use object-oriented design patterns in ps scripting https://dfinke.github.io/powershell,%20design%20patterns/2018/04/13/PowerShell-And-Design-Patterns.html
You need to include -PassThru when you are using -OutFile if you want something in your $response variable.
The exact purpose of PassThru from the PowerShell docs.
Indicates that the cmdlet returns the results, in addition to writing
them to a file. This parameter is valid only when the OutFile
parameter is also used in the command.
For example,
$response = Invoke-WebRequest -Uri 'www.google.com'
if ( $response.StatusCode -eq 200 )
{
#This bit runs for HTTP success
}
$response = Invoke-WebRequest -Uri 'www.google.com' -OutFile 'googleHome.html'
if ( $response.StatusCode -eq 200 )
{
#This never runs as $response never has a value even though the googleHome.html file gets created
}
$response = Invoke-WebRequest -Uri 'www.google.com' -OutFile 'googleHome.html' -PassThru
if ( $response.StatusCode -eq 200 )
{
#This bit runs for HTTP success and the file gets created
}

PowerShell: How can I determine if Invoke-WebRequest has timed out?

I need to produce some output when Invoke-WebRequest exceeds the time limit set by the -TimeoutSec parameter. How can I build an If condition that runs when this is the case?
In other words; what goes in place of ????? in the example below?:
Try {
Invoke-RestMethod -Uri $Uri -contentType "application/json"
-Method Post -Headers $Headers -Body $Body -TimeoutSec 8
}
Catch {
If (?????) {
Write-Host "the request timed out..."
}
}
In Windows PowerShell, the exception thrown will be a [System.Net.WebException] with the Status field set to Timeout:
try{
Invoke-WebRequest 'http://hostname.fqdn/really/slow/endpoint/' -TimeoutSec 3 -UseBasicParsing
}
catch [System.Net.WebException] {
if($_.Exception.Status -eq 'Timeout'){
# the request timed out
}
# something else went wrong during the web request
}

Exit from a command if it takes too much time in powershell

$uri="http:\\www.SomeUrl.com"
Measure-Command { $request = Invoke-WebRequest -Uri $uri -UseBasicParsing}
In above powershell script, how can I exit from Invoke-WebRequest if it takes time more than 10 secs, and return a error code if possible.
You can use the Timeout parameter to the Invoke-WebRequest command,
$uri="http://www.SomeUrl.com"
Measure-Command { $request = Invoke-WebRequest -Uri $uri -UseBasicParsing -Timeout 10}
You can cover it with try / catch block to get the error message.
try {
$uri="http://www.SomeUrl.com"
Measure-Command { $request = Invoke-WebRequest -Uri $uri -UseBasicParsing -Timeout 10 -ErrorAction Stop}
}
catch {
Write-Output "Timeout occured. Exception: $_"
}
You can also use -Headers #{"Cache-Control"="no-cache"} with Invoke-WebRequest which will not cache the pages you are visiting.

Unable to retrieve proper error from sharepoint using invoke-webrequest/restmethod

Upload a document into sharepoint using invoke-webrequest works but comes back with an unhelpful error when overwrite=false is used
I have used postman to send the same request and get back a sharepoint exception error
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code>-2130575257, Microsoft.SharePoint.SPException</m:code>
<m:message xml:lang="en-US">A file with the name docs/a.txt already exists. It was last modified by [redacted] on 08 Aug 2019 15:23:02 +0100.</m:message>
</m:error>
try
{
Invoke-webrequest -method post -uri $uri -infile $fullpath -headers $Headers -credential $credential
}
catch
{
$errors = $_.exception
}
instead of getting the error that is in postman I get "The remote server returned an error: (400) Bad Request."
I got around this by following the parserror function suggested here
How to get Powershell Invoke-Restmethod to return body of http 500 code response
function ParseErrorForResponseBody($Error) {
if ($PSVersionTable.PSVersion.Major -lt 6) {
if ($Error.Exception.Response) {
$Reader = New-Object System.IO.StreamReader($Error.Exception.Response.GetResponseStream())
$Reader.BaseStream.Position = 0
$Reader.DiscardBufferedData()
$ResponseBody = $Reader.ReadToEnd()
if ($ResponseBody.StartsWith('{')) {
$ResponseBody = $ResponseBody | ConvertFrom-Json
}
return $ResponseBody
}
}
else {
return $Error.ErrorDetails.Message
}
}
try
{
Invoke-restmethod -method post -uri $uri -infile $fullpath -headers $Headers -credential $credential
}
catch
{
ParseErrorForResponseBody($_)
}