How to change output of Invoke-WebRequest? - powershell

I want to be able to get the results of Invoke-WebRequest and have my script print either "Failed" if the server was not reached or "Online" if it was reached.
This is what I'm doing to try to do that.
$IW_Results = $Servers_to_Check | ForEach-Object { Invoke-WebRequest -Uri $_ }
$err = $IW_Results | ?{$_.gettype().Name -eq "ErrorRecord"}
if($err){
Write-Output "Failed"
}
else {
Write-Output "Online"
}
I was able to get the script to print "Online" if the server is reached. However when it can't be reached, my script wont print "Failed". Instead it will give me the error:
Invoke-WebRequest : Unable to connect to the remote server
At C:\Users\admin\Documents\VM-scripts\VM-tester.ps1:32
char:52
+ ... ts = $Servers_to_Check | ForEach-Object { Invoke-WebRequest -Uri $_ }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:Htt
pWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShe
ll.Commands.InvokeWebRequestCommand
How can I get the script to print out "Failed" instead of this error message?
Also the $Servers_to_Check variable is multiple servers

You need a Try Catch
$Servers_to_Check = "google.com", "asdasdf.asdfaa.sdf","yahoo.com"
$IW_Results = $Servers_to_Check | ForEach-Object {
try{
Invoke-WebRequest -Uri $_ | Out-Null
"Online"
}catch{
"Failed"
}
}
$IW_Results

Related

How to recycle appool when IIS getting slow response by using Powershell?

I am trying to write a script to check health of my web application's health status. Forexample if I couldn't get message in 10 seconds I have to recycle my apppool by using Powershell.Or except 200-ok codes, my app pool should recycled.
Please look at below code and ERROR:
# Load IIS module:
Import-Module WebAdministration
while ($true) {
write-host 'Runnig For Check app.xxx.com ...'
# First we create the request.
$HTTP_Request = [System.Net.WebRequest]::Create('https://app.xxx.com/')
Try
{
# We then get a response from the site.
$HTTP_Response = $HTTP_Request.GetResponse()
# We then get the HTTP code as an integer.
$HTTP_Status = [int]$HTTP_Response.StatusCode
If ($HTTP_Status -eq 200) {
Write-Host "Site is OK!"
}
Else {
Write-Host "The Site may be down, please check!"
Restart-WebAppPool -Name "app.xxx.com"
}
}
Catch
{
Stop-WebAppPool -Name "app.xxx.com"
Restart-WebAppPool -Name "app.xxx.com"
}
# Finally, we clean up the http request by closing it.
$HTTP_Response.Close()
Start-Sleep -Seconds 120
}
Error:
Restart-WebAppPool : You have to start stopped object before
restarting it. At C:\Scripts\CheckHealthHaydigo.ps1:25 char:6
+ Restart-WebAppPool -Name "app.xxx.com"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Restart-WebAppPool], InvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.IIs.PowerShell.Provider.RestartAppPoolCommand
It seems like you should check the status of the app pool before trying to restart it.
if ((Get-WebAppPoolState -Name "app.xxx.com").Value -eq "Stopped") {
Start-WebAppPool -Name "app.xxx.com"
}
else {
Restart-WebAppPool -Name "app.xxx.com"
}

powershell The underlying connection was closed: An unexpected error occurred on a send

I'm new to Powershell and created some breakpoints to figure out why the script times out. But I'm getting below error. Any help would be appreciated.
Exception calling "GetRequestStream" with "0" argument(s): "The
underlying connection was closed: An unexpected error occurred on a
send." At C:\Users\ksingh\Documents\SQL
scripts\pdfimportPowerShell.ps1:155 char:5
+ $requestStream = [System.IO.Stream]$request.GetRequestStream()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException
Here is part of the script and the error occurs at ---
bytes = [System.Text.Encoding]::ASCII.GetBytes($data)
function to call token service
function GetNewToken()
{
$request = [Net.WebRequest]::Create($temptokenserviceurl)
$request.ServicePoint.Expect100Continue = $false
$request.ContentType = "application/json"
$request.Method = "POST"
$data = (New-Object PSObject |
Add-Member -PassThru NoteProperty username $temptokenserviceuser |
Add-Member -PassThru NoteProperty password $temptokenservicepassword
) | ConvertTo-JSON
$bytes = [System.Text.Encoding]::ASCII.GetBytes($data)
$request.ContentLength = $bytes.Length
$requestStream = [System.IO.Stream]$request.GetRequestStream()
$requestStream.write($bytes, 0, $bytes.Length)
$response = $request.GetResponse()
$StreamReader = New-Object IO.StreamReader($response.getResponseStream())
$Json = $StreamReader.ReadToEnd()
$responseString = $Json | ConvertFrom-Json
$response.Close()
return $responseString.tokenId
}

PS Get-WinEvent throw 'The Handle is invalid'

I have a list of hostnames from which I'd like to extract all AppLocker related eventlogs, especially the ones with level warning and/or error.
I crafted this script:
$ComputersToCheck = Get-Content 'X:\ListWithTheNames.txt'
foreach($OneHost in $ComputersToCheck)
{
try
{
$EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EXE and DLL" -ComputerName $OneHost -Credential $CredentialFromUser
foreach ($SingelEvent in $EventCollection)
{
if($SingelEvent.LevelDisplayName -ne "Information")
{
$pathtosaveto = 'SomeFileName.txt'
$ResultString += $SingelEvent | Select Message,MachineName,UserId | Export-Csv -Path $pathtosaveto -Append
}
}
}
catch
{
//handling exceptions
}
}
This works for a while, but after a certain ammount of time I got an error:
Get-WinEvent : The remote procedure call failed
At X:\FileName.ps1:22 char:28
+ $EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EX ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : The remote procedure call failed,Microsoft.PowerShell.Commands.GetWinEventCommand
And right after the script start giving errors like this:
Get-WinEvent : The handle is invalid
At X:\FileName.ps1:22 char:28
+ $EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EX ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : The handle is invalid,Microsoft.PowerShell.Commands.GetWinEventCommand
My first thought was that it is related to the host the script try to reach, but the next in the list is the same type (Os, even the same model) as the previous.
I ran the script 3 times, and every time the output size was different (probably because not the same hosts were online with the same amount of logs).
The script should run against more than 700 hosts, to which a special account is needed which I prompt by the Get-Credential, store in a variable and pass it the the Get-WinEvent as a parameter.
To be honest I stuck with this issue, not really sure what cause this and why.
If anyone has an idea please share with me :)
Give this a try to attempt catching references to failed hosts and empty objects. You could write the exception received but I didn't include that in this to make the failedhosts file simple to read. Hope I got it right as I winged it and don't have a true case to test against.
$ComputersToCheck = Get-Content 'X:\ListWithTheNames.txt'
foreach($OneHost in $ComputersToCheck) {
try {
$EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EXE and DLL" -ComputerName $OneHost -Credential $CredentialFromUser -ErrorAction Stop
if($EventCollection) {
foreach ($SingelEvent in $EventCollection) {
if($SingelEvent.LevelDisplayName -ne "Information") {
$pathtosaveto = 'SomeFileName.txt'
$ResultString += $SingelEvent | Select Message,MachineName,UserId | Export-Csv -Path $pathtosaveto -Append
}
}
} else {
Out-File -InputObject $($OneHost + " Empty Event Collection") -FilePath "C:\FailedHosts.txt" -Append -Encoding ascii
}
}
catch {
Out-File -InputObject $($OneHost + " Failed Connection") -FilePath "C:\FailedHosts.txt" -Append -Encoding ascii
}
}

Restart-Computer to Email Body = Null, PowerShell

Attempting to run the follow script for a reboot I get the following error,
"Send-MailMessage : Cannot validate argument on parameter 'Body'. The argument is null or empty. Supply an arg
that is not null or empty and then try the command again.
At line:8 char:30
+ Send-MailMessage #messageParameters -BodyAsHtml
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Send-MailMessage], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.SendMailMessage"
Any help would be great!
Thanks
Cody
Restart-Computer -ComputerName nocconverter1 -Wait -For Wmi
$server = 'XXX'
ping -n 2 $server >$null
Function Server_Status_Check {
if($lastexitcode -eq 0) {
write-host "$server is ONLINE"
} else {
write-host "$server is OFFLINE/UNREACHABLE"
}
}
$messageParameters = #{
Subject = "Result: Reboot report for WebPeriop - $((Get-Date).ToShortDateString())"
Body = Server_Status_Check | out-string
From = "XXXX"
To = "XXXXX"
SmtpServer = "exmbx6"
}
Send-MailMessage #messageParameters -BodyAsHtml
Write-Host writes directly to the display. It doesn't write to stdout out therefore your Server_Status_Check function outputs nothing. Change it to:
Function Server_Status_Check {
if($lastexitcode -eq 0) {
"$server is ONLINE"
}
else {
"$server is OFFLINE/UNREACHABLE"
}
}

Catching dynamic exception types in PowerShell

I'm working on a PowerShell library that automates some network management operations. Some of these operations have arbitrary delays, and each can fail in unique ways. To handle these delays gracefully, I'm creating a generic retry function that has three main purposes:
Execute an arbitrary command (with parameters)
If it fails in a recognized way, try it again, up to some limit
If it fails in an unexpected way, bail and report
The problem is item #2. I want to be able to specify the expected exception type for the command. How can I do this in PowerShell?
Here's my function:
Function Retry-Command {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True, Position=0)]
[String] $name,
[Parameter(Mandatory=$True, Position=1)]
[String] $scriptBlock,
[String[]] $argumentList,
[Int] $maxAttempts=3,
[Int] $retrySeconds=10,
[System.Exception] $retryException=[System.Management.Automation.RuntimeException]
)
$attempts = 1
$keepTrying = $True
$cmd = [ScriptBlock]::Create($scriptblock)
do {
try {
&$cmd #argumentList
$keepTrying = $False
Write-Verbose "Command [$commandName] succeeded after $attmpts attempts."
} catch [$retryException] {
$msg = "Command [$commandName] failed. Attempt $attempts of $maxAttempts."
Write-Verbose $msg;
if ($maxAttempts -gt $attempts) {
Write-Debug "Sleeping $retrySeconds"
Start-Sleep -Seconds $retrySeconds
} else {
$keepTrying = $False
Write-Debug "Reached $attempts attempts. Re-raising exception."
Throw $_.Exception
}
} catch [System.Exception] {
$keepTrying = $False
$msg = "Unexpected exception while executing command [$CommandName]: "
Write-Error $msg + $_.Exception.ToString()
Throw $_.Exception
} finally {
$attempts += 1
}
} while ($True -eq $keepTrying)
}
I call it like this:
$result = Retry-Command -Name = "Foo the bar" -ScriptBlock $cmd -ArgumentList $cmdArgs
But this is the result:
Retry-Command : Cannot process argument transformation on parameter 'retryException'.
Cannot convert the "System.Management.Automation.RuntimeException" value of type "System.RuntimeType" to type "System.Exception".
At Foo.ps1:111 char:11
+ $result = Retry-Command <<<< -Name "Foo the bar" -ScriptBlock $cmd -ArgumentList $cmdArgs
+ CategoryInfo : InvalidData: (:) [Retry-Command], ParameterBindin...mationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Retry-Command
This seems to be saying that the type of [System.Management.Automation.RuntimeException] is not itself a [System.Exception], but is instead a [System.RuntimeType] which makes sense.
So, how do I specify the type of the exception to be caught?
It's not possible to use a variable as a catch criteria, it has to be a type-object (or something), everything else gives you an error. A workaround would be something like this:
#You can get the name of the exception using the following (or .Name for just the short name)
#PS > $myerr.Exception.GetType().Fullname
#System.UnauthorizedAccessException
function test {
param(
#Validate that specified name is a class that inherits from System.Exception base class
[ValidateScript({[System.Exception].IsAssignableFrom([type]$_)})]
$ExceptionType
)
try {
#Test-script, Will throw UnauthorizedAccessException when not run as admin
(Get-Content C:\test.txt) | % { $_ -replace 'test','lol' } | Set-Content C:\test.txt
}
catch [System.Exception] {
#Check if exceptiontype is equal to the value specified in exceptiontype parameter
if($_.Exception.GetType() -eq ([type]$ExceptionType)) {
"Hello. You caught me"
} else {
"Uncaught stuff: $($_.Exception.Gettype())"
}
}
}
A few tests. One with non-existing type, then with non-exception type, and finally a working one
PS > test -ExceptionType system.unaut
test : Cannot validate argument on parameter 'ExceptionType'. Cannot convert the "system.unaut" val
ue of type "System.String" to type "System.Type".
At line:1 char:21
+ test -ExceptionType system.unaut
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [test], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,test
PS > test -ExceptionType String
test : Cannot validate argument on parameter 'ExceptionType'. The "[System.Exception].IsAssignableF
rom([type]$_)" validation script for the argument with value "String" did not return true. Determin
e why the validation script failed and then try the command again.
At line:1 char:21
+ test -ExceptionType String
+ ~~~~~~
+ CategoryInfo : InvalidData: (:) [test], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,test
PS > test -ExceptionType UnauthorizedAccessException
Hello. You caught me