2

I am using Invoke-WebRequest in a SCOM PowerShell script to periodically monitor the availability of a URI. My script is fairly simple (since I have very little knowledge of PS :-) ):

$scomapi = new-object -comObject "MOM.ScriptAPI"
$scompb = $scomapi.CreatePropertyBag()
$fullHostName = "https://" + <full path to monitored web endpoint>
$result = Invoke-WebRequest $fullHostName
if($result.content) {
    $scompb.AddValue("ConfigurationReachable",$true);
} else {
    $scompb.AddValue("ConfigurationReachable",$false);
}           
$scomapi.AddItem($scompb) 
$scomapi.ReturnItems()

In order to test this script, I did manual changes in the hosts file on the client running the SCOM agent where I want to do the monitoring. Interestingly, the script succeeds in fetching the web endpoint even after the host is unreachable (tested this by pinging from that machine).

I did some further tests directly from the command line, and nothing changes. Even though I have no ping to the remote address, Invoke-WebRequest still succeeds and fetches the web page. So what am I doing wrong here?

vainolo
  • 6,907
  • 4
  • 24
  • 47

3 Answers3

6

Per discussion in the comments the issue is caching; only it's not the IP being cached that's the problem (at least, not the only problem); the content is also being cached; so instead of going to the web server to get your resource, the system's cheating and getting it locally. You can prevent this by adding -Headers @{"Cache-Control"="no-cache"} to your invoke-webrequest.

See example test script below; try running with and without the cache-control header before and after your hosts file tweak.

cls

$urlHost = 'server.mydomain.com'
$endpointUrl = ("https://{0}/path/to/resource.jpg" -f $urlHost)

#can be set once at the start of the script
[System.Net.ServicePointManager]::DnsRefreshTimeout = 0

#I don't have Clear-DnsClientCache; but the below should do the same thing
#Should be called inside any loop before the invoke-webrequest to ensure
#flush your machine's local dns cache each time
ipconfig /flushdns

#prove that our hosts update worked:
#optional, but will help in debugging
Test-Connection $urlHost -Count 1 | select ipv4address

#ensure we don't have a remembered result if invoke-request is in a loop
$result = $null
#make the actual call
#NB: -headers parameter takes a value telling the system not to get anything
#from the cache, but rather to send the request back to the root source.
$result = Invoke-WebRequest $endpointUrl -Headers @{"Cache-Control"="no-cache"}

#output the result; 200 means all's good (google http status codes for info on other values)
("`nHTTP Status Code: {0}`n" -f $result.StatusCode)

#output actual result; optional, but may be useful to see what's being returned (e.g. is it your page/image, or a 404 page / something unexpected
$result
JohnLBevan
  • 22,735
  • 13
  • 96
  • 178
6

I know this is old, but just in case this helps someone:

I ran across a similar issue, and adding "-Disable KeepAlive" resolved it for me.

Jared Lane
  • 81
  • 2
  • 9
  • There isn't a space in the flag i.e. `-DisableKeepAlive`. This seems to be more correct than the most upvoted answer since the other answer sets a request header, not response header. This approach worked for me, whereas the Headers approach didn't. – bart Sep 15 '21 at 20:45
1

Without testing it, I'd guess it's dns caching.

The powershell-session probably caches the ip on the first request and ignores your hosts-file update(just uses the old working ip).

Try running your script before and after disconnecting your network adapter/cable to simulate server failure.

UPDATE: What I'm trying to say above is that the script would work perfectly if the servers is unavailable, but your simulation using the hosts-file is giving a "false-positive" (so ignore the results).

If you really need to test the script with editing the hosts file, disable .Net dns cache in the session by adding the following line at the start of your script:

[System.Net.ServicePointManager]::DnsRefreshTimeout = 0
Frode F.
  • 52,376
  • 9
  • 98
  • 114
  • I'm running on VMs but have no access to the hypervisor (I can get access but it will take me some time). Any idea how to clear the powershell-session? Is there some option to clear it or maybe use another command that does not use the cache? – vainolo Sep 01 '13 at 11:40
  • Strange... doesn't work. I also tried executing `Clear-DnsClientCache` but nothing happens. Thanks anyway. – vainolo Sep 01 '13 at 12:02
  • how are you running it? is the script running multiple times in the same session? because `$result` isn't cleared when it fails on the second time. `$result` keeps the values/object from the last working attempt, so your content test would always be true if the script is looping in the same powershell session. try clearing `$res = null` before invoking – Frode F. Sep 01 '13 at 14:53
  • I used `clear-variable` before each run. I also replayed everything in a clean PS window, with the same results. The cache was still there. – vainolo Sep 02 '13 at 06:31
  • Then I can't help you, since I can't reproduce it here. I tried `Invoke-webrequest` with the setting in my answer enabled and it worked fine : / – Frode F. Sep 03 '13 at 14:20
  • The answer should be working, so I guess the problem is on my side. Thanks! – vainolo Sep 03 '13 at 14:42