1

I'm using Windows 2003 Server x86, Powershell 1.0 and have following head-breaking problem. When I'm trying to execute script below, I'm getting an error:

Error "=" operator: System error. (Fehler beim "="-Operator: Systemfehler.)
+ $data =  <<<< Get-Content $log | % {

Here is this script:

$log = "C:\log file.txt"
$linePrefix = "PROCESS THIS LINE"
$trimStart = 25 #chars to ignore in the beginning
$started = 0

$data = Get-Content $log | % { 
    if ($_.length -ge $trimstart) { 
        $linedata = $_.substring($trimstart);
        $timesline = $linedata.startswith($lineprefix); 
        if ($started -eq 0 -and $timesline) { 
            $started = 1; 
        }
        if ($started) { 
            if ($timesline) { 
                $line = $linedata.substring($lineprefix.length).trimstart();
                if ($line.contains(": ")) {
                    write-output $line 
                } 
            } else { 
                break; 
            }
        }
    }
}

However, if I execute it without $data = assignment, it works perfectly and returns me expected values. I've also tried following statements

$data = (...)
$data = $(...)

and declaring a function with expression but without success.

Could you please give me a hint why it does happen?

UPDATE: I've tried to remove spaces before and after assigment sign and got similar error, but now powershell didn't like $data=G string

Error "=" operator: System error (Fehler beim "="-Operator: Systemfehler.)
At C:\kosmo\scripts\ps\test.ps1:60 Symbol:7
+ $data=G <<<< et-Content $log | % {
kosmo
  • 101
  • 2
  • 9
  • have you tried executing it all in one line? – Musaab Al-Okaidi Feb 12 '13 at 15:53
  • yeap. I've prepared one-liner for it: `$data = Get-Content $log | % { if ($_.length -ge $trimstart) { $linedata = $_.substring($trimstart); $timesline = $linedata.startswith($lineprefix); if ($started -eq 0 -and $timesline) { $started = 1; }; if ($started) { if ($timesline) { $line = $linedata.substring($lineprefix.length).trimstart(); if ($line.contains(": ")) { write-output $line } } else { break; } } } }`. still nothing – kosmo Feb 12 '13 at 15:54
  • Tried $data = &{...} ? – mjolinor Feb 12 '13 at 15:55
  • "Still nothing" Do you mean you get the same error? Is there any chance you can try on a newer version of powershell as it's not throwing any errors for me on Powershell 3 – Musaab Al-Okaidi Feb 12 '13 at 15:57
  • Yeap. Same error. I've updated my question with new info. I've tried also `&{..}` with same output. Pity, I can live only on 2003 server and there is no choice - you can use only PSv1.0, AFAIK – kosmo Feb 12 '13 at 16:07
  • What happens if you remove 'break'? – Shay Levy Feb 12 '13 at 16:08
  • I would advise to update to PS2.0 on your server, so you can use all the improvements. PS1.0 is hard for most people to advise on here since it's very outdated. Win2003 SP2 or higher supports it. Check out this link for download links. http://www.microsoft.com/en-us/download/details.aspx?id=4045 – Frode F. Feb 12 '13 at 16:20

3 Answers3

0

I've converted your code into a function that will return a String object. So you can run it as follows:

$data = Parse-LogFile

You will need to import the function into your shell first, you can do that by simply copying and pasting it in.

Function Parse-LogFile
{
   $log = gc "C:\log file.txt"
   $linePrefix = "PROCESS THIS LINE"
   $trimStart = 25 #chars to ignore in the beginning
   $started = 0
   $ReturnText = New-Object System.Text.StringBuilder
   foreach ( $line in $log )
   {
      if ($_.length -ge $trimstart)
      {
         $linedata = $_.substring($trimstart);
         $timesline = $linedata.startswith($lineprefix);

         if ($started -eq 0 -and $timesline) 
         { 
            $started = 1; 
         }

         if ($started) 
         { 
            if ($timesline)
            {
               $line = $linedata.substring($lineprefix.length).trimstart();
               if ($line.contains(": "))
               {
                  $ReturnText.Append($line)
                  $ReturnText.AppendLine()
               }
            }
            else
            {
               break;
            }
         }
      }
   }

   Retrun $ReturnText.ToString()
}
Musaab Al-Okaidi
  • 3,734
  • 22
  • 21
  • Thanks, but I still need it as a bunch of lines, not as a single string. I want to provide this data as parameter to a couple of statistics functions – kosmo Feb 12 '13 at 16:40
  • The string object is a bunch of lines, you can iterate through it just like we iterate through the $log variable which is also a string object. – Musaab Al-Okaidi Feb 12 '13 at 17:01
  • Thanks, but I want to avoid using `foreach`-statement, it iterates whole collection before staring processing; that's why I need to use `ForEach-Object`-cmdlet – kosmo Feb 13 '13 at 10:41
  • I don't think that's right. foreach and foreach-object work pretty much the same. Have you got an example of how they don't work in the same way? – Musaab Al-Okaidi Feb 13 '13 at 11:00
  • When some things seem to work the same, it isn't obvious that those things are the same. [Differences between foreach-statement and ForEach-Object Cmdlet](http://www.windowsitpro.com/content1/topic/iterating-through-collections-with-powershell-s-foreach-loops-99873/catpath/windows-powershell/page/2) – kosmo Feb 13 '13 at 15:06
0

Although I cannot reproduce your issue on my machines, I think the problem might be related to your use of break within the pipeline during an assignment. As a first test, if you remove the break, does it change things?

Going on the assumption that this is indeed the issue, you can refactor slightly to avoid doing the assignment directly. Instead, you could build up your $data variable from within the loop itself.

$log = ".\logfile.log"
$linePrefix = "PROCESS THIS LINE"
$trimStart = 25 #chars to ignore in the beginning
$started = 0
$data = @()  # initialize blank data array

Get-Content $log | % { 
    if ($_.length -ge $trimstart) { 
        $linedata = $_.substring($trimstart);
        $timesline = $linedata.startswith($lineprefix); 
        if ($started -eq 0 -and $timesline) { 
            $started = 1; 
        }
        if ($started) { 
            if ($timesline) { 
                $line = $linedata.substring($lineprefix.length).trimstart();
                if ($line.contains(": ")) {
                    # add to your result here
                    $data += $line 
                } 
            } else { 
                break; 
            }
        }
    }
}

Now $data contains what you want. This might not be the best-performing code, depending on how many results you are expecting, but it might give you a start.

latkin
  • 16,402
  • 1
  • 47
  • 62
  • Thanks for a helpful hint about break! I've found out some useful info from it, detailed in my answer – kosmo Feb 13 '13 at 10:33
0

Thanks all to your hints! Pity, but nothing suggested solved my problem indeed. Most helpful was hint from latkin about break behavior. After some reading I found out, that in Foreach-Object cmdlet, which is aliased by %, break or continue statements stop whole script

function getFilteredResult {

    1..50 | % { 
        if ($_ -le 20) { 
            if (($_ % 2) -eq 0) {
                write-output $_;
            }
        } else {
            break; #terminates whole script, you don't even get "after got result"
            #continue; #save result as break
        }
    }   
}

Write-Host "before getting result"

$result = getFilteredResult

$result | % {$i=0}{ ++$i; Write-Host "$i) $_" }

Write-Host "after got result"

Output shows only before getting result. From there I've made a conclusion that there is no way to do what I want in Powershell 1.0! So I found a way to install Powershell 2.0 on my good old 2003 server (tip how to uninstall Powershell 1.0 before; btw, my Windows-update had name KB926140-v5).

Ok, error has gone. But I still have no result I want to have?! At the end of my journey I found very useful post and have written script below

function getFilteredResult {
    Try {
        1..50 | % { 
            if ($_ -le 20) { 
                if (($_ % 2) -eq 0) {
                    write-output $_;
                }
            } else {
                #break; #terminates whole script, you don't even get "after got result"
                #continue; #terminates whole script, you don't even get "after got result"
                throw "terminated pipeline!"
            }
        }   
    } Catch {
        #ignore terminated pipeline exception
    }
}

Write-Host "before getting result"

$result = getFilteredResult

$result | % {$i=0}{ ++$i; Write-Host "$i) $_" }

Write-Host "after got result"

And got an answer:

before getting result
1) 2
2) 4
3) 6
4) 8
5) 10
6) 12
7) 14
8) 16
9) 18
10) 20
after got result

Explanation If I'd used foreach statement, I could use break with estimated behavior, but I'm working with large log files and foreach-statement reads whole file into memory, while ForEach-Object cmdlet processes lines one by one. I'm not sure about Get-Content cmdlet, maybe it also reads whole file to return it, but I've written down my own cmdlet Get-Content-Reversed to read lines from the end of file and that's why I'm pretty sure it doesn't

Community
  • 1
  • 1
kosmo
  • 101
  • 2
  • 9