使用PowerShell替换文本文件中的字符串

时间:2017-05-09 06:06:20

标签: powershell powershell-v2.0

我在服务器的某个位置有一个文本文件。该文件包含字符串值和时间戳。 我想使用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."
        }
    }
}

6 个答案:

答案 0 :(得分:9)

您可以使用正则表达式

执行此操作
$filePath = 'yourPath'
(Get-Content $filePath -raw) -replace '([^|]+).*', ('$1|{0:MM-dd-yyyy HH-mm-ss}' -f (Get-Date)) |
    Set-Content $filePath

Regex explanation

enter image description here

答案 1 :(得分:3)

由于您的文件用作数据库,因此您应该使用基于CSV的存储,首先是因为您有用于来回解析CSV的cmdlet,即Import-CSVExport-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脚本:输入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

可能可以修复。

  1. 您使用-replace搜索的字符串需要是正则表达式。 |字符在正则表达式中是特殊的,需要进行转义。我会在一个单独的行上编写正则表达式并将其存储在名为$ regex的变量中,所以我不会忘记。

  2. 您希望在来自Get-Content的每一行上运行替换,因此需要使用%(“foreach-object”的缩写)在单独的管道步骤中完成。

  3. 我会使用字符串插值来形成字符串。这是可选的,但我会告诉你我的意思......

  4. 我认为Path应该是变量,而不是文件的文字名称。

  5. 在单个管道中获取和设置同一文件的内容可能会导致冲突。在两条不同的线上进行操作是最简单的。

  6. 固定版本可能如下所示:

    $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中有特殊字符...
    此外,此脚本不会在最后两行执行之间的时间段内保持文件锁定,因此某些其他应用程序可能在其间更新它。对于文本文件,最后一个作者获胜,因此如果发生冲突,可能会丢失一些更新。