我在服务器的某个位置有一个文本文件。该文件包含字符串值和时间戳。 我想使用PowerShell将此特定行替换为最新的时间戳。
以下是记事本文件的数据:
Test Service|05-09-2017 01-09-41
这里05-09-2017 01-09-41是MM-dd-yyyy HH-mm-ss,我想用最新的时间戳替换这一行。
所以,如果两分钟后它应该是
Test Service|05-09-2017 01-11-41
这是我正在做的事情:
$ReplaceString = "$ServiceName + "|" + (Get-Date).ToString('MM-dd-yyyy HH-mm-ss')"
Get-Content Path -Replace($ServiceName + "|" + $StringLastRunTime,$ReplaceString) | Set-Content Path
但它不会产生预期的输出。
更新
很抱歉没有明确的要求
我想使用PowerShell脚本监控服务器上安装的关键服务。我已在一个文本文件中列出了要监视的所有服务,并且该脚本中已提到该路径。此脚本将每5分钟执行一次,如果未安装服务或服务已停止,则会生成电子邮件通知。为防止电子邮件泛滥,我正在考虑使用文本文件中的服务名称更新时间戳。 因此,如果我发现一个服务处于停止模式或未安装,我将发送通知并更新上次发送时间的时间戳。我有一个重发间隔,每五分钟检查一次,如果该间隔通过,我必须再次发送通知,我想更新时间戳。
代码(我已删除电子邮件发送部分以使其不那么复杂):
$ServicesList = Get-Content E:\ServiceReports\Services.txt
$ResendEmailInterval = 10 #In Minutes
foreach ($Service in $ServicesList) {
$ServiceName = $Service
$Service = Get-Service -Display $Service -ErrorAction SilentlyContinue
$serviceDisplayName = $Service.displayname
if (-Not $Service) {
#Service is not installed. So need to send an email alert and update the timestamp.
Write-Host $ServiceName.IndexOf("|")
if ($ServiceName.IndexOf("|") -gt 0) {
$ServiceName,$StringLastRunTime = $ServiceName.Split('|')
$LastRunTime = [datetime]::ParseExact($StringLastRunTime, "MM-dd-yyyy HH-mm-ss", $null)
Write-Host $ServiceName
Write-Host $LastRunTime
Write-Host (Get-Date).AddMinutes($ResendEmailInterval)
if ($LastRunTime -lt (Get-Date).AddMinutes($ResendEmailInterval)) {
Write-Host "time to run"
$ReplaceString = $ServiceName + "|" + (Get-Date).ToString('MM-dd-yyyy HH-mm-ss')
Write-Host $ServiceName"|"$StringLastRunTime
Write-Host $ReplaceString
#$ServiceName = "Test Service";
$ReplaceString = "{0}|{1}" -f $ServiceName, (Get-Date).ToString('MM-dd-yyyy HH-mm-ss');
(Get-Content -Path $ServicesListPath) -replace ('([^|]+).*', $ReplaceString) | Set-Content $ServicesListPath;
$ServicesList -replace ($ServiceName + "|" + $StringLastRunTime, $ReplaceString) | Set-Content $ServicesListPath
}
} else {
$ReplaceString = $ServiceName + "|" + (Get-Date).ToString('MM-dd-yyyy HH-mm-ss')
$ServicesList -replace ($ServiceName, $ReplaceString) | Set-Content $ServicesListPath
$i = $i+1;
}
} else {
if ($Service.Status -eq "Stopped") {
Write-Host "Service is stopped"
#Time to send email and update the time stamp
$i = $i+1;
} else {
#Write-Host "Service is running. Nothing to do."
}
}
}
答案 0 :(得分:9)
您可以使用正则表达式:
执行此操作$filePath = 'yourPath'
(Get-Content $filePath -raw) -replace '([^|]+).*', ('$1|{0:MM-dd-yyyy HH-mm-ss}' -f (Get-Date)) |
Set-Content $filePath
答案 1 :(得分:3)
由于您的文件用作数据库,因此您应该使用基于CSV的存储,首先是因为您有用于来回解析CSV的cmdlet,即Import-CSV
和Export-CSV
,因为使用CSV,您可以保存列的类型信息。通过这种方式,您可以生成一次正确的CSV,然后运行Import-CSV
生成PSObject
个数组,然后处理每个更新时间戳(get-date)
或[DateTime]::Now
,然后你可以Export-CSV
覆盖已保存的数据,可以将其另存为备份和工作副本。像这样:
$ServicesList=Import-CSV E:\ServiceReports\Services.txt -encoding UTF8
foreach ($service in $serviceslist) {
# a PSObject expected to have "Service" and "Timestamp" fields
$servicename=$service.service
$ts=$service.timestamp
if ($ts -eq "") { $ts=get-date "01.01.2000 00:00:00" }
$sysservice=get-service -displayname $servicename -ea silentlycontinue
if (-not $sysservice) {
if ($ts -lt [DateTime]::Now.AddMinutes(-1*$ResendEmailInterval)) {
# send email - no service
$service.timestamp=[DateTime]::Now # just that
}
} elseif ($sysservice.status -eq 'Stopped') {
write-host "Service $servicename is stopped"
if ($ts -lt [DateTime]::Now.AddMinutes(-1*$ResendEmailInterval)) {
# send email - service stopped
$service.timestamp=[DateTime]::Now # update timestamp
}
} else {
#service is running, set timestamp to "zero"
$service.timestamp=get-date "01.01.2000 00:00:00"
}
}
$ServicesList | Export-CSV E:\ServiceReports\Services.txt -encoding UTF8
在此之前,请使用以下内容填写文件,提供您要监控的服务的实际名称:
"Service","Timestamp"
"First service",""
"Second service",""
...
答案 2 :(得分:3)
我想使用PowerShell脚本监控服务器上安装的关键服务。
由于这似乎是您编写所有脚本的动机,我会告诉您一种更好的方法来监控服务,而不是将时间戳写入文件:
PowerShell
作为程序,c:\path\to\your\script.ps1
作为参数。答案 3 :(得分:1)
查看您提供的代码,但不知道实际输出是什么,我希望您的$ReplaceString
出错。你的报价没有加起来。这应该适用于它:
$ReplaceString = $ServiceName + "|" + (Get-Date).ToString('MM-dd-yyyy HH-mm-ss')
答案 4 :(得分:0)
您添加到说明中的代码似乎不起作用。此外,我建议对字符串使用格式化运算符。
$ServiceName = "Test Service";
$ReplaceString = "{0}|{1}" -f $ServiceName, (Get-Date).ToString('MM-dd-yyyy HH-mm-ss');
(Get-Content -Path $Path) -replace ('([^|]+).*', $ReplaceString) | Set-Content $Path;
答案 5 :(得分:0)
好的,你的榜样......
$ReplaceString = "$ServiceName + "|" + (Get-Date).ToString('MM-dd-yyyy HH-mm-ss')"
Get-Content Path -Replace($ServiceName + "|" + $StringLastRunTime,$ReplaceString) | Set-Content Path
可能可以修复。
您使用-replace
搜索的字符串需要是正则表达式。 |
字符在正则表达式中是特殊的,需要进行转义。我会在一个单独的行上编写正则表达式并将其存储在名为$ regex的变量中,所以我不会忘记。
您希望在来自Get-Content的每一行上运行替换,因此需要使用%(“foreach-object”的缩写)在单独的管道步骤中完成。
我会使用字符串插值来形成字符串。这是可选的,但我会告诉你我的意思......
我认为Path
应该是变量,而不是文件的文字名称。
在单个管道中获取和设置同一文件的内容可能会导致冲突。在两条不同的线上进行操作是最简单的。
固定版本可能如下所示:
$regex = "^$([regex]::Escape($serviceName))\|.*"
$ReplaceString = "${ServiceName}|$((Get-Date).ToString('MM-dd-yyyy HH:mm:ss'))"
$result = Get-Content $Path | %{ $_ -replace($regex,$ReplaceString)}
Set-Content $Path -Value $result
P.S。 [regex] :: Escape部分是为了防止ServiceName中有特殊字符...
此外,此脚本不会在最后两行执行之间的时间段内保持文件锁定,因此某些其他应用程序可能在其间更新它。对于文本文件,最后一个作者获胜,因此如果发生冲突,可能会丢失一些更新。