我正在尝试创建一个 powershell 脚本,以便在每次运行脚本时仅将与模式(可以是一行或多行)匹配的新条目从一个文件复制到另一个文件。源文件由应用程序随机更新,但请求是每小时复制最后的条目。
我正在研究的解决方案是获取文件中存储的上一次运行的最后一个条目,并与文件中的最后一个条目进行比较,如果它们不匹配,则开始复制该行之后的新行。这就是我被卡住的部分,我不知道如何表示,而是每次都复制整个内容。
这是我到目前为止得到的:
Write-Host "Declaring the output log file ..... " -ForegroundColor Yellow
$destinationfile = 'C:\file\out\output.log'
Write-Host "Getting the last line of the source file ..... " -ForegroundColor Yellow
$sourcefile = 'C:\app\blade\inputlogs.log'
$sourcefilelastline = Get-Content $originfile | Select-Object -last 1
$sourcefilelastline
Write-Host "Getting the last line of the destination file ..... " -ForegroundColor Yellow
$destinationfilelastline = Get-Content $destinationfile | Select-Object -last 1
$destinationfilelastline
if ($sourcefilelastline -eq $destinationfilelastline){
Write-Host "Skipping the process ..... " -ForegroundColor Yellow
}
else{
Write-Host "Reading the source log file and updating destination file ..... " -ForegroundColor Yellow
$sourcefilecontent = Get-Content -Path $sourcefile | Where-Object { $_ -ne '' } | Select-String -Pattern 'error' -CaseSensitive -SimpleMatch
$sourcefilecontent | Add-Content $destinationfile
}
关于如何完成这件事有什么想法吗?谢谢。
这是一个小小的实验,但似乎效果很好。
Read-LastLinesOfTextFile 函数:
function Read-LastLinesOfTextFile {
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$AppName,
[Parameter(Mandatory = $true, Position = 1)]
[string]$TextFile
)
$RegistryPath = "HKCU:\Software\$AppName" # Registry key path for storing registry value
if (-not (Test-Path "$RegistryPath")) { # If key path does not exists
$null = New-Item -Path $RegistryPath -Force # Then create registry key
}
# Check if the registry value for LastPosition does NOT exists - https://stackoverflow.com/a/43921551/4190564
if ( (Get-ItemProperty "$RegistryPath").PSObject.Properties.Name -notcontains "LastPosition" ) {
# Create LastPosition value
$null = New-ItemProperty -Path $RegistryPath -Name "LastPosition" -Value 0 -PropertyType DWORD -Force
}
# Save registry value LastPosition to $LastPosition
$LastPosition = Get-ItemPropertyValue -Path $RegistryPath -Name "LastPosition"
$CurrentFileSize = (Get-Item $TextFile).Length # Get current file size
if ($CurrentFileSize -lt $LastPosition) { # If the file is smaller than it used to be
$LastPosition = 0 # Then assume it was deleted and now has all new data.
} elseif ($CurrentFileSize -lt $LastPosition) {
return @()
}
# Open file stream
try { $FileStream = New-Object System.IO.FileStream($TextFile, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read) }
catch { return @() }
# Open stream reader
try { $StreamReader = New-Object System.IO.StreamReader($FileStream) }
catch {
$FileStream.Close() # Close FileStream
return @()
}
$Return = @() # Define default return value of empty array
try {
if ($LastPosition) { # If LastPosition anything other than 0
# Seek last position
$null = $FileStream.Seek($LastPosition, [System.IO.SeekOrigin]::Begin)
}
$Text = $StreamReader.ReadToEnd() # Read to the end of the file
# Update the registry with the new last position
Set-ItemProperty -Path $RegistryPath -Name "LastPosition" -Value $FileStream.Position
$Return = $Text -split "\r?\n" # Split string into lines. https://stackoverflow.com/a/76831908/4190564
}
finally {
$StreamReader.Close() # Close StreamReader
$FileStream.Close() # Close FileStream
}
return $Return
}
要调用此函数,请使用类似于以下内容的行,只需确保将
MyLogReader
替换为您的脚本特有的名称,这样您就不会与使用相同函数的其他脚本发生冲突。看起来您正在与“错误”进行区分大小写的比较,因此我在本示例中使用了 -cmatch
。如果您希望不区分大小写,请将其更改为 -match
。
Read-LastLinesOfTextFile 'MyLogReader' "$PSScriptRoot\MyLogFile.LOG" | Where-Object { $_ -cmatch 'error' } | Add-Content $destinationfile
Get-content 有一个开关“tail”,可让您从文件中读取最后几行。根据微软自己的话:
Tail 参数获取文件的最后一行。此方法比检索变量中的所有行并使用 [-1] 索引表示法更快。
您可以在您的案例中从底线开始使用它,直到它们匹配为止。
function Get-FileLastContent {
param (
[Parameter(
Position = 0,
Mandatory = $true,
HelpMessage = 'Path to File')]
[ValidateScript({ Test-Path -Path $_ })]
[string]
$FilePath,
[Parameter(
Position = 1,
HelpMessage = 'Number of lines lines to check')]
[ValidateNotNullOrEmpty()]
[int]
$LastLines = 1
)
$FileContent = Get-Content -Path $FilePath -Tail $LastLines
Return $FileContent
}
Write-Host -Object "Declaring the output log file ..... " -ForegroundColor Yellow
$destinationfile = 'C:\file\out\output.log'
Write-Host -Object "Getting the last line of the destination file ..... " -ForegroundColor Yellow
$destinationfilelastline = Get-FileLastContent -FilePath $destinationfile
$destinationfilelastline
$LastLines = 1
Write-Host -Object "Getting the last line of the source file ..... " -ForegroundColor Yellow
$sourcefile = 'C:\app\blade\inputlogs.log'
$sourcefilelastline = Get-FileLastContent -FilePath $sourcefile -LastLines $LastLines
Write-Host -Object $sourcefilelastline
if (($sourcefilelastline -ne $destinationfilelastline)) {
Write-Host -Object "Reading the source log file and updating destination file ..... " -ForegroundColor Yellow
while ($sourcefilelastline[0] -ne $destinationfilelastline) {
$LastLines=$LastLines+1
$sourcefilelastline = Get-FileLastContent -FilePath $sourcefile -LastLines $LastLines
}
#$sourcefilelastline = $sourcefilelastline | Where-Object { $_ -ne '' } | Select-String -Pattern 'error' -CaseSensitive -SimpleMatch
$sourcefilelastline= $sourcefilelastline | Select-Object -Skip 1
@("`n") + $sourcefilelastline | Add-Content -Path $destinationfile -Force -Encoding UTF8 -NoNewline
}
else {
Write-Host -Object "Skipping the process ..... " -ForegroundColor Yellow
}