0

Have a command that (on 2008 boxes) throws an exception due to the buffer limit.

Essentially, the script stops WAUA, blows out SoftwareDistribution, then reaches out to rebuild SD and check for updates against WSUS then checks back in so the alerts in WSUS stop.

I want a specific line to retry if an exception is thrown until it finishes without an exception, then we can tell it to report back in to WSUS to clear it out.

Stop-Service WUAUSERV
Remove-Item -Path C:\WINDOWS\SoftwareDistribution -recurse
Start-Service WUAUSERV
GPUpdate /force
WUAUCLT /detectnow
sleep 5

## This is the command I'd like to loop, if possible, when an exception is thrown ##
$updateSession = new-object -com "Microsoft.Update.Session"; $updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates

WUAUCLT /reportnow 

Any kind of help would be appreciated. Everything I've been able to find has been how to create my own exception but not how to handle it when an exception is thrown and retry until it finishes without an error.



Edit:

Then based on the below Answer, is this how I would want it to be written so it will continue to check until it runs successfully and then it'll report back in?

Stop-Service WUAUSERV
Remove-Item -Path C:\WINDOWS\SoftwareDistribution -recurse
Start-Service WUAUSERV
GPUpdate /force
WUAUCLT /detectnow
sleep 5
while(-not $?) {$updateSession = new-object -com "Microsoft.Update.Session"; $updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates}
WUAUCLT /reportnow

2 Answers2

1

You can use the special character $? This will return false if the last command returned with error, so your while loop would just look like:

while(-not $?)

See what is $? in powershell.

Alternatively, $error[0] gives the last thrown error message so you could build a while loop around that, similar to:

while($error[0] -ne "error message")
AutomatedOrder
  • 501
  • 4
  • 14
  • But wouldn't a While loop in this case need to be something like this: while (-not $?) {$updateSession = new-object -com "Microsoft.Update.Session"; $updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates } that way it'll run until it's successful? – Anthony Lombardi Mar 06 '20 at 20:08
1

Set a value to false and only flip it if you get total success. Loop until you succeed or your timeout exceeds your defined value -- if you don't include a timeout, you have created an infinite loop condition where if the host never succeeds, it'll run until reboot.

$sts = $false
$count = 0
do {
    try {
        $updateSession = new-object -com "Microsoft.Update.Session"
        $updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates
        $sts = $true
    } catch {
        ## an exception was thrown before we got to $true
    }

    $Count++
    Start-Sleep -Seconds 1
} Until ($sts -eq $true -or $Count -eq 100)
thepip3r
  • 2,855
  • 6
  • 32
  • 38
  • Would I need to include the 'Finally' block in this? or does the Until take care of it so it's not necessary? – Anthony Lombardi Mar 06 '20 at 20:44
  • You don't *need* Finally{} at all. When I use finally, it's to Dispose() or Close() objects that need to be disposed or closed regardless of whether the commands succeeded or failed (release resources, etc.). You'd have to look at $UpdateSession and $Updates to see if they implement IDisposable or .Close() – thepip3r Mar 06 '20 at 20:47
  • Gotcha. So what you are having it do is retry 100 times until it's successful, then it'd automatically move on to the next line accordingly, correct? sleep 5 WUAUCLT /reportnow – Anthony Lombardi Mar 06 '20 at 20:52
  • well, the condition is OR so if $UpdateSession and $Updates both don't throw an exception, then the loop will exit the first time. However, if they error out 100 times, over ~100 seconds, the loop will also terminate so it doesn't run forever. Please adjust the seconds or number of iterations to your liking. – thepip3r Mar 06 '20 at 20:54
  • When using this today for the first time (new to the company, this was shared by a co-worker) at times it took 2 or 3 minutes to run once on that line. it'd fail and I'd need to run it again. and again. they had just recently updated to a new WSUS box so the point is to blow it out and begin "fresh" form the new box and forget the old one. I guess it just has so many updates it'll throw an exception at times. figured there'd be a good way to loop it until it's successful so you don't need to babysit – Anthony Lombardi Mar 06 '20 at 20:56
  • How should I modify the time? On some servers it ran within 30 seconds. Others it took a few minutes. I'm going to reduce the retry to 5 or 10 attempts, but the time I'm now questioning. – Anthony Lombardi Mar 06 '20 at 21:19
  • Sleep time is irrelevant. Specify whatever is good for you. If it fails and you want it to wait for a minute before retrying, change the seconds param to 60. If you only want it to retry 10 times instead of 100, delete a 0. – thepip3r Mar 06 '20 at 21:25
  • Retry quantity is based on the experience you're having interacting with the faulty server. You shouldn't be experiencing exceptions. As you are, we're introducing code that will retry and hopefully eventually succeed (evidenced by what you do manually). The number of times to retry is based on what you've seen doing it manually before it succeeds. The limit is just a guarantee it wont' run indefinitely. – thepip3r Mar 06 '20 at 21:25
  • Understood. First try on some, others it took 3 or 4 runs before it was successful. I'll keep it at 10 for shiggles for now, until we need to re-run it in a couple weeks . I did the 20 or so servers manually today. I appreciate the help. I'll report back in a couple weeks if this didn't end up working. I'm also going to do some digging on my own to see if I can test the loop using other parameters so I understand it better. Thank you. – Anthony Lombardi Mar 06 '20 at 21:37