PS1替换或删除单个字符,而无需重写整个文件

时间:2019-04-24 21:32:01

标签: powershell

是否可以使用PowerShell 1删除或替换文件最后一个非空白行上的最后一个字符?

我正在尝试获取精确到5分钟内的正常运行时间日志。

我发现有一些内置的日志和命令可以通过命令提示符访问,这些命令可以告诉我上次启动计算机的时间或何时正确关闭计算机,但是本机正常运行时间日志仅记录一次每24小时一次,因此,如果发生电源故障,我将不知道该系统脱机多长时间(其精度比24小时更精确)。

所以我创建了以下脚本:

$bootTime = (Get-WmiObject Win32_OperatingSystem).LastBootUpTime
$formBootTime = [Management.ManagementDateTimeConverter]::ToDateTime($bootTime)
$uptime = (Get-Date)-$formBootTime
"$formBootTime,$(Get-Date),{0:00},{1:00},{2:00},{3:00}" -f $uptime.Days,$uptime.Hours,$uptime.Minutes,$uptime.Seconds >> C:\UptimeTracker.csv

但是,当我想评估我的机器在过去X天内已经运行了多长时间时,滚动浏览这冗长的时间。

所以我想我应该添加一个标记来标识每个给定Boot的当前或最近的Uptime日志。

但是,要使其正常工作,我需要能够在先前的记录不再是相关记录时删除该标记。

$bootTime = (Get-WmiObject Win32_OperatingSystem).LastBootUpTime
$formBootTime = [Management.ManagementDateTimeConverter]::ToDateTime($bootTime)
$file = (Get-Content c:\UptimeTracker.csv | Measure-Object)
$numberOfLines = $file.Count
$numberOfWords = (Get-Content c:\UptimeTracker.csv | Select -Index ($numberOfLines -1) | Measure-Object -word)
$Line = Get-Content c:\UptimeTracker.csv | Select -Index ($numberOfLines -2)
$wordArray = $Line.Split(",")
$LastLineBT = $wordArray[0]
if($LastLineBT -eq $formBootTime) {
    $unmark = "true"
}
else
{$unmark = "false"}

if($unmark == "true"){ <remove last character of file> }

$uptime = (Get-Date)-$formBootTime 
"$formBootTime,$(Get-Date),{0:00},{1:00},{2:00},{3:00},X" -f $uptime.Days,$uptime.Hours,$uptime.Minutes, $uptime.Seconds >> C:\UptimeTracker.csv

以上内容中的某些内容是从https://stackoverflow.com/a/16210970/11035837

借来并修改的

我已经看到了几种接收文件作为输入文件并写入不同输出文件的方法,从那里可以很容易地通过脚本重命名新旧文件来切换它们的位置(新,旧的,待命的-轮流使用)我不重写整个文件的原因是为了减少那些命令/脚本被中断且操作未完成的实例。理想情况下,只有在电源出现故障时,操作才能完成。但是,我已经在以前的版本中看到过,它偶尔会跳过5分钟的间隔,最长可达15分钟,而上次报告的引导时间没有任何变化。 我怀疑这与阻止任务计划程序运行脚本的其他更高优先级的进程有关。如果是这种情况,那么在脚本执行过程中完全重写文件会导致部分失败的现有日志数据,而我宁愿错过最新记录而不是所有数据。

我没有发现任何东西可以删除/替换最后一个字符(或两个,因为一个是换行字符),我也没有发现任何明确声明这是不可能的东西-我发现了声明未经完全重写就无法选择替换内部内容或开始内容。

除非有任何解决方案的最终答案,否则如果无法确定,那么我将尝试以下操作:

if($unmark == "true"){     
    $input = "C:\UptimeTracker_CUR.csv"
    $output = "C:\UptimeTracker_NEW.csv"

    $content = Get-Content $input
    $content[-2] = $content[-2] -replace 'X', ' '
    $content | Set-Content $output
    Rename-Item -Path "C:\UptimeTracker_CUR.csv" -NewName "C:\UptimeTracker_SBY.csv"
    Rename-Item -Path "C:\UptimeTracker_NEW.csv" -NewName "C:\UptimeTracker_CUR.csv"
}

编辑-由于TheMadTechnician多次阅读评论

...
$file = Get-Content c:\UptimeTracker.csv
$fileMeasure = ($file | Measure-Object)
$numberOfLines = $fileMeasure.Count
$numberOfWords = ($file | Select -Index ($numberOfLines -1) | Measure-Object -word)
$Line = $file | Select -Index ($numberOfLines -2)
...
...
if($unmark == "true"){     
    $output = "C:\UptimeTracker_NEW.csv"

    $file[-2] = $file[-2] -replace 'X', ' '
    $file | Set-Content $output
    Rename-Item -Path "C:\UptimeTracker.csv" -NewName "C:\UptimeTracker_SBY.csv"
    Rename-Item -Path "C:\UptimeTracker_NEW.csv" -NewName "C:\UptimeTracker.csv"
}

1 个答案:

答案 0 :(得分:0)

您多次读取了整个文件,这必须减慢整个脚本的速度。我建议读入整个文件,确定是否需要清除标志,然后在输出时进行,将新行添加到文件中。假设您仍未运行PowerShell v2,则可以执行以下操作:

$bootTime = (Get-WmiObject Win32_OperatingSystem).LastBootUpTime
$formBootTime = [Management.ManagementDateTimeConverter]::ToDateTime($bootTime)
$uptime = (Get-Date)-$formBootTime
$File = Get-Content c:\UptimeTracker.csv -raw
if($File.trim().split("`n")[-1].Split(',')[0] -eq $formBootTime){
    $File.trim() -replace 'X(?=\s*$)',' '
}else{
    $File.Trim()
},("$formBootTime,$(Get-Date),{0:00},{1:00},{2:00},{3:00},X" -f $uptime.Days,$uptime.Hours,$uptime.Minutes, $uptime.Seconds)|Set-Content c:\UptimeTracker.csv

如果您正在运行旧版本,则-raw将没有Get-Content选项。作为解决方案,您可以改为执行此操作,并且相同的解决方案仍应起作用。

$bootTime = (Get-WmiObject Win32_OperatingSystem).LastBootUpTime
$formBootTime = [Management.ManagementDateTimeConverter]::ToDateTime($bootTime)
$uptime = (Get-Date)-$formBootTime
$File = (Get-Content c:\UptimeTracker.csv) -Join "`n"
if($File.trim().split("`n")[-1].Split(',')[0] -eq $formBootTime){
    $File.trim() -replace 'X(?=\s*$)',' '
}else{
    $File.Trim()
},("$formBootTime,$(Get-Date),{0:00},{1:00},{2:00},{3:00},X" -f $uptime.Days,$uptime.Hours,$uptime.Minutes, $uptime.Seconds)|Set-Content c:\UptimeTracker.csv

这将变慢,因此应被视为辅助选项,因为您将必须以字符串数组的形式读取整个文件,并将其转换为单个多行字符串。