2

I just started working with Powershell and this is my first script.

I am checking for 3 strings in last 50 lines of a log file. I need to find all three strings and print error message if any one of those is missing. I have written following script but it does not give me the expected results.

(Get-Content C:\foo\bar.log )[-1..-50] | Out-File C:\boom\shiva\log.txt
$PO1 = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P01_RCV> ok"}
$PO2 = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P02_SND> ok"}
$PO3 = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P03_RCV> ok"}

I am satisfied with above piece of code. The problem is with the below. I dont want to use if-else thrice. I am struggling to draft a for loop which can save space and still give me the same result.

if (!$PO1)
{
    "PO1 is critical"
}
else
{
    "PO1 is OK"
}
if (!$PO2)
{
    "PO2 is critical"
}
else
{
    "PO2 is OK"
}
if (!$PO3)
{
    "PO3 is critical"
}
else
{
    "PO3 is OK"
}

Can someone gave me small example of how i can fit these 3 if-else in one for loop.

4 Answers 4

4

If you only want to find out that all 3 strings are present this script will also show which one is missing.
(binary encoded in the variable $Cnt)

## Q:\Test\2018\07\13\SO_51323760.ps1
##
$Last50 = Get-Content 'C:\foo\bar.log' | Select-Object -Last 50
$Cnt = 0

if ($Last50 -match "<Ping:AD_P01_RCV> ok"){$Cnt++}
if ($Last50 -match "<Ping:AD_P02_SND> ok"){$Cnt+=2}
if ($Last50 -match "<Ping:AD_P03_RCV> ok"){$Cnt+=4}

if ($cnt -eq 7){
   "did find all 3 strings "
} else {
   "didn't find all 3 strings ({0})" -f $cnt
}

Variant immediately complaining missing P0(1..3)

$Last50 = Get-Content 'C:\foo\bar.log' | Select-Object -Last 50

if (!($Last50 -match "<Ping:AD_P01_RCV> ok")) {"PO1 is critical"}
if (!($Last50 -match "<Ping:AD_P02_SND> ok")) {"PO2 is critical"}
if (!($Last50 -match "<Ping:AD_P03_RCV> ok")) {"PO3 is critical"}

Sorry I'm a bit slow this monday.

To check in a loop different variables by building the variable name:

1..3| ForEach-Object {
  If (!(Get-Variable -name "P0$_").Value){"`$P0$_ is critical"}
}
Sign up to request clarification or add additional context in comments.

4 Comments

Hi Lot. Thanks for this solution however i want to identify which one is missing as well. Also for some reason i get result "didn't find all 3 strings" even though all 3 strings are present.
What number was trailing the message? Testing locally with your above output works correct returning (5) when I remove the line with snd.
my apologies Lot... got 'did find all 3 strings' output... Can you suggest how i can point out if any individual string (PO1 / PO2 / PO3) is missing... Also it would be fantastic if you could tell me how i can loop the 3 variables in a for loop as my original question...
I appended another script which checks in a loop which variable is empty
1

What you're trying to do is better addressed with a hashtable than with individually named variables.

$data = Get-Content 'C:\boom\shiva\log.txt'

$ht = @{}
1..3 | ForEach-Object {
    $key = 'P{0:d2}' -f $_
    $str = if ($_ -eq 2) {"${key}_SND"} else {"${key}_RCV"}
    $ht[$key] = $data -match "<ing:AD_${str}> ok"
}

$ht.Keys | ForEach-Object {
    if ($ht[$_]) {
        "${key} found in log."
    } else {
        "${key} not found in log."
    }
}

You can check if all lines were present at least once with something like this:

if (($ht.Values | Where-Object { $_ }).Count -lt 3) {
    'Line missing from log.'
}

Comments

0

PSv3 introduced the -Tail (-Last) parameter to Get-Content, which is the most efficient way to extract a fixe number of lines from the end of a file.

You can pipe its output to Select-String, which accepts an array of regex patterns, any of which produces a match (implicit OR logic).

$matchingLines = Get-Content -Tail 50 C:\foo\bar.log |
  Select-String '<Ping:AD_P01_RCV> ok', '<Ping:AD_P02_SND> ok', '<Ping:AD_P03_RCV> ok'

if ($matchingLines) { # at least 1 of the regexes matched
   $matchingLines.Line  # output the matching lines
} else {  # nothing matched
  Write-Warning "Nothing matched."
}

Comments

0

I finally got below draft that resolved my query to cycle variables through a for loop. I finally had to convert those individual variables to a array. But htis gives me expected result. Basically i need this script to provide input to my Nagios plugin which needs minor modification but its done.

(Get-Content C:\foo\bar.log )[-1..-50] | Out-File C:\boom\shiva\log.txt
$j = 1
$PO = new-object object[] 3
$PO[0] = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P01_RCV> ok"}
$PO[1] = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P02_SND> ok"}
$PO[2] = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P03_RCV> ok"}
foreach( $i in $PO){
    if (!$i){
        "PO "+$j+" is CRITICAL"}
    else{
        "PO "+$j+" is OK"}
    $j+=1
}

Thank you LotPings, Ansgar and mklement0 for your support and responses. I picked up a few things from your answers.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.