I've tried invoke-restmethod
, new-object
and many other methods to achieve what I'm trying to do. Here are the latest two iterations:
$req = Invoke-WebRequest -uri $scripturl -OutFile "$($scriptpath)\fls.core.ps1"
Write-Host "StatusCode:" $req.StatusCode
$req = Invoke-WebRequest -uri $scripturl -OutFile "$($scriptpath)\fls.core.ps1" | Select-Object -Expand StatusCode
Write-Host "StatusCode:" $req
Basically I'm attempting to download another PowerShell script and execute it. So obviously it needs to be synchronous. I also need the status so I can determine if it updated or not.
Here is pseudo code for what I'm trying to accomplish:
try {
download file
} catch {
output error
if (local copy exists) {
log warning that local copy is being used
} else {
log error could not download and no local copy available
exit script
}
}
run script (only after downloading new one if available)
Here is my current code in full:
$param1=$args[0]
if ($param1 -eq "-d" -or $param1 -eq "-D") {
$isDev = $true
}
#todo: Move to config file
$logpath = "c:\company\logs\loginscript"
$scriptpath = "c:\company\scripts\"
$scripturl = "http://downloads.company.com/fls.core.ps1"
$logfile="$(Get-Date -Format "yyyy-MM-dd hhmmss").log"
Function log($message) {
Write-Output "[$(Get-Date -Format "yyyy-MM-dd hhmmss")] $message" | Out-file "$($logpath)\$($logfile)" -append
if ($isDev) { Write-Host "[$(Get-Date -Format "yyyy-MM-dd hhmmss")] $message" }
}
Function createFolder($path) {
if (-!(Test-Path $path)) { New-Item -Type Directory -Path $path }
}
function updateScripts() {
try {
$req = Invoke-WebRequest -uri $scripturl -OutFile "$($scriptpath)\fls.core.ps1"
Write-Host "StatusCode:" $req.StatusCode
} catch {
Write-Host "StatusCode:" $req.StatusCode
if ($req.StatusCode -eq 404) {
log "WARNING: Script not found at $scripturl"
} else {
log "ERROR: Script download error: $req.StatusCode"
}
if (Test-Path "$($scriptpath)\fls.core.ps1") {
log "WARNING: Using local script"
} else {
log "ERROR: Unable to update script and no local script found. Exiting."
exit
}
}
}
#----------------------------------------------#
#---- MAIN CODE BLOCK -------------------------#
#----------------------------------------------#
createFolder $logpath
createFolder $scriptpath
#update scripts
updateScripts
#execute core loginscript
& $scriptpath/fls.core.ps1
$req.StatusCode
appears to be null.
Invoke-WebRequest
reports errors as statement-terminating errors, which means that no assignment to variable $req
(in statement $req = Invoke-WebRequest ...
) takes place in case an error occurs.
Update:
In PowerShell (Core) 7+, you can now use the -SkipHttpErrorCheck
switch to suppress the error and get a response object back as usual, whose .StatusCode
property contains the HTTP status code; e.g.:
# PS 7+ only: -> 404
(Invoke-WebRequest -SkipHttpErrorCheck http://example.org/nosuchpage).StatusCode
The following applies to Windows PowerShell (but the technique still works in PowerShell (Core)).
Instead, unfortunately, if an error occurs, the response object[1] must be gleaned from the [ErrorRecord]
instance representing the error, which is available via $Error[0]
after the fact, or via $_
in the catch
block of a try { ... } catch { ... }
statement (adapted from this answer):
try {
Invoke-WebRequest -Uri $scripturl -OutFile "$scriptpath\fls.core.ps1"
} catch [Microsoft.PowerShell.Commands.HttpResponseException] {
# Get the status code...
$statuscode = $_.Exception.Response.StatusCode
# ... and work with it.
# if ($statusCode -eq 404) { ...
} catch {
# Unexpected error, re-throw
throw
}
Strictly speaking, $_.Exception.Response.StatusCode
returns a value from an enumeration type, System.Net.HttpStatusCode
, not an [int]
value, but you can use it like an integer. To return an integer to begin with, append .Value__
or cast to [int]
.
Note that Invoke-WebRequest
is always synchronous; if you download a file (successfully), the call won't return until the download is completed.
[1] As the linked answer explains, the response object contained in the error record is of a different type than the one that Invoke-WebRequest
returns in case of success (which requires -PassThru
if -OutFile
is also specified): The error record's .Exception.Response
property contains a System.Net.Http.HttpResponseMessage
instance, whereas Invoke-WebRequest
returns an instance (derived from) Microsoft.PowerShell.Commands.WebResponseObject
, which incorporates an instance of the former type, in its .BaseResponse
property.