Restart application pool based on http response code - powershell

I am trying to write a PowerShell script that will restart an application pool in IIS if a 503 response code is received.
So far I have managed to retrieve the response code for every crm application under the default website in IIS. However I am unsure how I would go about finding the application pool name. I've tried the below, but it returns the same application pool for each site. Can anyone help?
$getSite = (Get-WebApplication -Site 'Default Web Site')
$SiteURL = ForEach ($site in $getSite.path) {("http://localhost")+$site}
ForEach ($crm in $SiteURL){
$req = [system.Net.WebRequest]::Create($crm)
try {
$res = $req.GetResponse()
} catch [System.Net.WebException] {
$res = $_.Exception.Response
}
$ApplicationPool = ForEach ($app in $getSite.applicationpool) {$app}
if([int]$res.StatusCode -eq 503) {write-host ($crm + ' ' + [int]$res.StatusCode) + $app}
}

I think you need to access $_.Exception.InnerException for the the Response property.
Your $ApplicationPool assignment doesn't make much sense, as you would only need one applicationPool name per $crm app you test:
foreach($App in #(Get-WebApplication -Site 'Default Web Site')){
# Uri for the application
$TestUri = 'http://localhost{0}' -f $App.path
# Create WebRequest
$Request = [system.Net.WebRequest]::Create($TestUri)
try {
# Get the response
$Response = $Request.GetResponse()
} catch [System.Net.WebException] {
# If it fails, get Response from the Exception
$Response = $_.Exception.InnerException.Response
}
# The numerical value of the StatusCode value is the HTTP status code, ie. 503
if(503 -eq ($Response.StatusCode -as [int])){
# Restart the app pool
Restart-WebAppPool -Name $App.applicationPool
}
}

Related

URL health-check PowerShell script correctly gets HTTP 200 on most sites, but incorrect '0' status code on some...API timeout issue?

I have a URL health-checking PowerShell script which correctly gets an HTTP 200 status code on most of my intranet sites, but a '0' status code is returned on a small minority of them. The '0' code is an API return rather than from the web site itself, according to my research of questions from others who have written similar URL-checking PowerShell scripts. Thinking this must be a timeout issue, where API returns '0' before the slowly-responding web site returns its 200, I've researched yet more questions about this subject area on SO and implemented a suggestion from someone to insert a timeout in the script. The timeout setting though, no matter how high I set the timeout value, doesn't help. I still get the same '0' "response" code from the same web sites even though those web sites are up and running as checked from any regular web browser. Any thoughts on how I could tweak the timeout setting in the script below in order to get the correct 200 response code?
The Script:
$URLListFile = "C:\Users\Admin1\Documents\Scripts\URL Check\URL_Check.txt"
$URLList = Get-Content $URLListFile -ErrorAction SilentlyContinue
#if((test-path $reportpath) -like $false)
#{
#new-item $reportpath -type file
#}
#For every URL in the list
$result = foreach($Uri in $URLList) {
try{
#For proxy systems
[System.Net.WebRequest]::DefaultWebProxy = [System.Net.WebRequest]::GetSystemWebProxy()
[System.Net.WebRequest]::DefaultWebProxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
#Web request
$req = [system.Net.WebRequest]::Create($uri)
$req.Timeout=5000
$res = $req.GetResponse()
}
catch {
#Err handling
$res = $_.Exception.Response
}
$req = $null
#Getting HTTP status code
$int = [int]$res.StatusCode
# output a formatted string to capture in variable $result
"$int - $uri"
#Disposing response if available
if($res){
$res.Dispose()
}
}
# output on screen
$result
#output to log file
$result | Set-Content -Path "C:\Users\Admin1\Documents\Scripts\z_Logs\URL_Check\URL_Check_log.txt" -Force
Current output:
200 - http://192.168.1.1/
200 - http://192.168.1.2/
200 - http://192.168.1.250/config/authentication_page.htm
0 - https://192.168.1.50/
200 - http://app1-vip-http.dev.local/
0 - https://CA/certsrv/Default.asp
Perhaps using PowerShell cmdlet Invoke-WebRequest works better for you. It has many more parameters and switches to play around with like ProxyUseDefaultCredentials and DisableKeepAlive
$pathIn = "C:\Users\Admin1\Documents\Scripts\URL Check\URL_Check.txt"
$pathOut = "C:\Users\Admin1\Documents\Scripts\z_Logs\URL_Check\URL_Check_log.txt"
$URLList = Get-Content -Path $pathIn
$result = foreach ($uri in $URLList) {
try{
$res = Invoke-WebRequest -Uri $uri -UseDefaultCredentials -UseBasicParsing -Method Head -TimeoutSec 5 -ErrorAction Stop
$status = [int]$res.StatusCode
}
catch {
$status = [int]$_.Exception.Response.StatusCode.value__
}
# output a formatted string to capture in variable $result
"$status - $uri"
}
# output on screen
$result
#output to log file
$result | Set-Content -Path $pathOut -Force

How to run a web request using default credentials in Powershell

I am working on the following code.
$HTTP_Request =[System.Net.WebRequest]::Create('http://google.com')
$HTTP_Response = $HTTP_Request.GetResponse()
$HTTP_Status = [int]$HTTP_Response.StatusCode
echo $HTTP_Status
But I want to run it using my default credentials, because there are few URLs which returns 401 ,that is client not authorized and for that I need it to run using my default credentials.
Can anyone help me regarding same, as I want to store the status of some URLs and this code is working fine except for those which are protected.
So the question was to run web request while using default credentials, here are the solutions I found:
for powershell 2.0:-
$req = [system.Net.WebRequest]::Create($uri)
$req.UseDefaultCredentials = $true
try
{
$res = $req.GetResponse()
}
catch [System.Net.WebException]
{
$res = $_.Exception.Response
}
$int = [int]$res.StatusCode
echo $int
For Powershell 3.0:-
try{
$res = Invoke-WebRequest $uri -UseDefaultCredentials
}
catch [System.Net.WebException]
{
$res = $_.Exception.Response
}
$int = [int]$res.StatusCode
echo $int
Both scripts are extremely doing well but if you want to find code status of many URLs, then you should go for powershell 3.0 , it handles web-requests in a much better way.

How do you get the response from a 404 page requested from powershell

I have to call an API exposed by TeamCity that will tell me whether a user exists. The API url is this: http://myteamcityserver.com:8080/httpAuth/app/rest/users/monkey
When called from the browser (or fiddler), I get the following back:
Error has occurred during request processing (Not Found).
Error: jetbrains.buildServer.server.rest.errors.NotFoundException: No user can be found by username 'monkey'.
Could not find the entity requested. Check the reference is correct and the user has permissions to access the entity.
I have to call the API using powershell. When I do it I get an exception and I don't see the text above. This is the powershell I use:
try{
$client = New-Object System.Net.WebClient
$client.Credentials = New-Object System.Net.NetworkCredential $TeamCityAgentUserName, $TeamCityAgentPassword
$teamCityUser = $client.DownloadString($url)
return $teamCityUser
}
catch
{
$exceptionDetails = $_.Exception
Write-Host "$exceptionDetails" -foregroundcolor "red"
}
The exception:
System.Management.Automation.MethodInvocationException: Exception calling "DownloadString" with "1" argument(s): "The remote server returned an error: (404) Not Found." ---> System.Net.WebException: The remote server returned an error: (404) Not Found.
at System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request)
at System.Net.WebClient.DownloadString(Uri address)
at CallSite.Target(Closure , CallSite , Object , Object )
--- End of inner exception stack trace ---
at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
I need to be able to check that the page is returned contains the text described above. This way I know whether I should create a new user automatically or not.
I could just check for 404, but my fear is that if the API is changed and the call really returns a 404, then I would be none the wiser.
Change your catch clause to catch the more specific WebException, then you can use the Response property on it to get the status code:
{
#...
}
catch [System.Net.WebException]
{
$statusCode = [int]$_.Exception.Response.StatusCode
$html = $_.Exception.Response.StatusDescription
}
BrokenGlass gave the answer, but this might help:
try
{
$URI='http://8bit-museum.de/notfound.htm'
$HTTP_Request = [System.Net.WebRequest]::Create($URI)
"check: $URI"
$HTTP_Response = $HTTP_Request.GetResponse()
# We then get the HTTP code as an integer.
$HTTP_Status = [int]$HTTP_Response.StatusCode
}
catch [System.Net.WebException]
{
$statusCode = [int]$_.Exception.Response.StatusCode
$statusCode
$html = $_.Exception.Response.StatusDescription
$html
}
$HTTP_Response.Close()
Response:
check: http://8bit-museum.de/notfound.htm
404
Not Found
another approach:
$URI='http://8bit-museum.de/notfound.htm'
try {
$HttpWebResponse = $null;
$HttpWebRequest = [System.Net.HttpWebRequest]::Create("$URI");
$HttpWebResponse = $HttpWebRequest.GetResponse();
if ($HttpWebResponse) {
Write-Host -Object $HttpWebResponse.StatusCode.value__;
Write-Host -Object $HttpWebResponse.GetResponseHeader("X-Detailed-Error");
}
}
catch {
$ErrorMessage = $Error[0].Exception.ErrorRecord.Exception.Message;
$Matched = ($ErrorMessage -match '[0-9]{3}')
if ($Matched) {
Write-Host -Object ('HTTP status code was {0} ({1})' -f $HttpStatusCode, $matches.0);
}
else {
Write-Host -Object $ErrorMessage;
}
$HttpWebResponse = $Error[0].Exception.InnerException.Response;
$HttpWebResponse.GetResponseHeader("X-Detailed-Error");
}
if i understand the question then $ErrorMessage = $Error[0].Exception.ErrorRecord.Exception.Message contains the errormessage you are looking for.
(source: Error Handling in System.Net.HttpWebRequest::GetResponse() )
Another simple example, hope this helps:
BEGIN
{
# set an object to store results
$queries = New-Object System.Collections.ArrayList
Function Test-Website($Site)
{
try
{
# check the Site param passed in
$request = Invoke-WebRequest -Uri $Site
}
catch [System.Net.WebException] # web exception
{
# if a 404
if([int]$_.Exception.Response.StatusCode -eq 404)
{
$request = [PSCustomObject]#{Site=$site;ReturnCode=[int]$_.Exception.Response.StatusCode}
}
else
{
# set a variable to set a value available to automate with later
$request = [PSCustomObject]#{Site=$site;ReturnCode='another_thing'}
}
}
catch
{
# available to automate with later
$request = [PSCustomObject]#{Site=$site;ReturnCode='request_failure'}
}
# if successful as an invocation and has
# a StatusCode property
if($request.StatusCode)
{
$siteURI = $Site
$response = $request.StatusCode
}
else
{
$response = $request.ReturnCode
}
# return the data
return [PSCustomObject]#{Site=$Site;Response=$response}
}
}
PROCESS
{
# test all the things
$nullTest = Test-Website -Site 'http://www.Idontexist.meh'
$nonNullTest = Test-Website -Site 'https://www.stackoverflow.com'
$404Test = Test-Website -Site 'https://www.stackoverflow.com/thispagedoesnotexist'
# add all the things to results
$queries.Add($nullTest) | Out-Null
$queries.Add($nonNullTest) | Out-Null
$queries.Add($404Test) | Out-Null
# show the info
$queries | Format-Table
}
END{}
Output:
Site Response
---- --------
http://www.Idontexist.meh another_thing
https://www.stackoverflow.com 200
https://www.stackoverflow.com/thispagedoesnotexist 404
You could try using the Internet Explorer COM object instead. It allows you to check the browser return codes and navigate the HTML object model.
Note: I've found that you need to run this from an elevated PowerShell prompt in order to maintain the COM object definition.
$url = "http://myteamcityserver.com:8080/httpAuth/app/rest/users/monkey"
$ie = New-Object -ComObject InternetExplorer.Application
Add this to See the browser
$ie.visibility = $true
Navigate to the site
$ie.navigate($url)
This will pause the script until the page fully loads
do { start-sleep -Milliseconds 250 } until ($ie.ReadyState -eq 4)
Then verify your URL to make sure it's not an error page
if ($ie.document.url -ne $url) {
Write-Host "Site Failed to Load" -ForegroundColor "RED"
} else {
[Retrieve and Return Data]
}
You can navigate HTML Object model via $ie.document. Using Get-Member and HTML methods such as GetElementsByTagName() or GetElementById().
If credentials are an issue, build this into a function then use Invoke-Command with the -Credentials parameter to define your logon information.

Powershell httplistener handle more than one request at the same time

I´m using a normal powershell httplistener script.
The script listenes on port 80 and gives an response.
Now I tried to handle more than one request as the same time. The problem is that the second respons has to wait until the first response was finished by the script.
I tried to start an own job for every http-request - but I can´t send a response to the listener from the PS-Job.
Does anyone know, how to handle parallel httprequests in PS?
Here is the Script I´m using:
$url = 'http://localhost/'
$listener = New-Object System.Net.HttpListener
$listener.Prefixes.Add($url)
$listener.Start()
Write-Host "Listening at $url..."
while ($listener.IsListening)
{
$context = $listener.GetContext()
$requestUrl = $context.Request.Url
$response = $context.Response
Write-Host ''
Write-Host "> $requestUrl"
$localPath = $requestUrl.LocalPath
$route = $routes.Get_Item($requestUrl.LocalPath)
if ($route -eq $null)
{
$response.StatusCode = 404
}
else
{
$content = & $route
$buffer = [System.Text.Encoding]::UTF8.GetBytes($content)
$response.ContentLength64 = $buffer.Length
$response.OutputStream.Write($buffer, 0, $buffer.Length)
}
$response.Close()
$responseStatus = $response.StatusCode
Write-Host "< $responseStatus"
}
What is the right way to handle more than one request at the same time?
Thanks #all!
You can use multiple runspaces (even the runspace pool) within the same PowerShell process. See this blog post for details on how to do that.
Check the $request.url.LocalPath or another one of the url properties depending on how much of context you are looking for.
Provide a different response depending on the request.
$htmlout = "<html><link rel=""stylesheet"" href=""MyStleSheet.css""><body class=""body"" />Hello World</body></html>"
$css = ".body {background-color: white;font-size: 20px;font-family: calibri;}"
while($Listener.IsListening -and $noBreak){
$Context = $listener.GetContext()
$request = $context.request
if($request.url.LocalPath -match '.css')
{
$buffer = [System.Text.Encoding]::utf8.getbytes($css)
}
if($request.url.LocalPath -match '.html')
{
$buffer = [System.Text.Encoding]::utf8.getbytes($htmlout)
}
$response = $context.response
$response.contentlength64 = $buffer.length
$response.OutputStream.Write($buffer,0,$buffer.length)
}

Powershell Command: HttpWebRequest stucks after fetching two requests

I have a list of URL in a text file and I want to test whether all of them are reachable or not. I fired the following command in windows powershell but somehow after displaying the status of first two requests, the command stucks somewhere and never returns. Am I missing something?
cat .\Test.txt | % { [system.Net.WebRequest]::Create("$_").GetResponse().StatusCode }
Text File
http://www.google.com
http://www.yahoo.com
http://www.bing.com
Output:
OK
OK
----> after that it stucks.
use Invoke-WebRequest instead:
$sites = 'http://www.google.com','http://www.yahoo.com','http://www.bing.com'
foreach ($site in $sites) {
Invoke-WebRequest $site
$site
}
From memory: You have to explicitly close the Response stream:
$req = [System.Net.HttpWebRequest]::Create($aRequestUrl);
$response = $null
try
{
$response = $req.GetResponse()
# do something with the response
}
finally
{
# Clear the response, otherwise the next HttpWebRequest may fail... (don't know why)
if ($response -ne $null) { $response.Close() }
}