Question

As a novice in powershell coding, I have some difficulties with expansion of a variable in PowerShell regex patterns.

What I wanted to do is:

  • Scan for logfiles that have been changed between two timeframes
  • For each of the logfiles, I get part of the name which indicates the date it is referencing to.

That date is stored in the variable $filedate. Then go trough each line logfiles Whenever I find a line that looks like:

14:00:15 blablabla

In a file named blabla20130620.log I want that the data line becomes

2013-06-20 14:00:15 blablabla

It should write the output in append mode to a text file (to concatenate different log files)

Here is what I got until now (I'm testing in a sandbox now, so no comments etc...)

$Logpath = "o:\Log"
$prevcheck="2013-06-24 19:27:14"
$currenttd="{0:yyyy-MM-dd HH:mm:ss}" -f (get-date)
$batch = 1000
[regex]$match_regex = '^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)'
If (Test-Path "$Logpath\test.txt"){
Remove-Item "$Logpath\test.txt"
}

$files=Get-ChildItem $LogPath\*.log | Where-Object { $_.LastWriteTime -ge "$prevcheck" -   and $_.LastWriteTime -le "$currenttd" -and !$_.PSIsContainer }
foreach ($file in $files)
{
$filedate=$file.Name.Substring(6,4) + "-" + $file.Name.Substring(10,2) + "-" +   $file.Name.Substring(12,2)

## This doesn't seem to work fine
## results look like:
## "$filedate" 14:00:15 blablabla

$replace_regex = '"$filedate" $_'

## I tried this too, but without success
## The time seems to dissappear now
## results look like:
## 2013-06-20  blablabla 

#$replace_regex = iex('$filedate' + $_)

(Get-Content $file.PSPath -ReadCount $batch) |
 foreach-object {if ($_ -match $match_regex) { $_ -replace $match_regex, $replace_regex}      else { $_ }}|
out-file -Append "o:\log\test.txt"
Was it helpful?

Solution 2

You're over-complicating things.

  • You're comparing dates in your Where-Object filter, so you don't need to transform your reference dates to strings. Just use dates:

    $prevcheck = Get-Date "2013-06-24 19:27:14"
    $currenttd = Get-Date
    
  • You can use a regular expression to extract the date from the file name and transform it into the desired format:

    $filedate = $file.BaseName -replace '^.*(\d{4})(\d{2})(\d{2})$', '$1-$2-$3'
    
  • Your regular expression for matching the time is overly correct. Use ^(\d{2}:\d{2}:\d{2}) instead. It's a little sloppier, but it will most likely suffice and is a lot easier on the eye.

  • To prepend the time-match with the date, use "$filedate `$1". The double quotes will cause $filedate to be expanded to the date from the file name, and the escaped $ (``$1`) will keep the grouped match (see Richard's explanation).

  • While you can assign the results from each step to variables, it'd be simpler to just use a single pipeline.

Try this:

$Logpath   = "o:\Log"
$Logfile   = "$Logpath\test.txt"
$prevcheck = Get-Date "2013-06-24 19:27:14"
$currenttd = Get-Date

If (Test-Path -LiteralPath $Logfile) { Remove-Item $Logfile }

Get-ChildItem "$LogPath\*.log" | ? {
  -not $_.PSIsContainer -and
    $_.LastWriteTime -ge $prevcheck -and
    $_.LastWriteTime -le $currenttd
} | % {
  $filedate = $_.BaseName -replace '^.*(\d{4})(\d{2})(\d{2})$', '$1-$2-$3'
  Get-Content $_ | % {
    $_ -replace '^(\d{2}:\d{2}:\d{2})', "$filedate `$1"
  } | Out-File -Append $Logfile
}

OTHER TIPS

In PowerShell strings have to be in double quotes (") for variable substitution. Single quoted (') strings do not perform variable substitution.

In your script (in which I suggest you indent the content of code blocks to make the structure easier to follow):

$replace_regex = '"$filedate" $_'

where the string is single quoted, so no variable substitution. This can be fixed by remembering the back-quote (`) character can be used to escape double quotes embedded in a double quoted string:

$replace_regex = "`"$filedate`" $_"

But remember:

  • $ is a regex meta-character, so if you want to include a $ in a regex in double quotes it will need to be escaped to avoid PSH treating it as the start of the variable name.
  • Any regex meta-characters in the variable will have their regex meaning. Consider escaping the content of the variable before substitution ([regex]::Escape(string)).
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top