2017-05-09 69 views
7

我在服务器上的某个位置有一个文本文件。该文件包含一个字符串值和一个时间戳。 我想用PowerShell替换这个特定的行和最新的时间戳。使用PowerShell替换文本文件中的字符串

下面是记事本文件中的数据:

 
Test Service|05-09-2017 01-09-41 

这里2017年5月9日41年1月9日是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 

但它不会产生预期的输出。

UPDATE

对不起,我不是符合要求

我想监控安装使用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

这是由什么产生的实际输出? – Seth

+0

你可以粘贴整个脚本吗? – 30000MONKEYS

+0

@ 30000MONKEYS更新 –

回答

0

看你提供的代码,并在不知道实际的输出是什么,我希望你$ReplaceString是错误。你的报价不加起来。这应该为它工作:

$ReplaceString = $ServiceName + "|" + (Get-Date).ToString('MM-dd-yyyy HH-mm-ss') 
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

你能解释我的正则表达式部分 –

+0

@RanadipDutta检查我添加到答案的链接。 –

+0

谢谢.. @ Martin –

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; 
+0

我已经用更多的描述,代码和用例更新了这个问题 –

3

由于您的文件作为一个数据库,你应该使用一个基于CSV存储,首先是因为你需要解析的CSV到的cmdlet来回回,即Import-CSVExport-CSV,第二因为CSV你能够保存列的类型信息。这样你就可以生成正确的CSV一次,然后运行Import-CSV产生一个PSObject的数组,然后你处理它们中的每一个用(get-date)[DateTime]::Now更新时间戳,然后你覆盖保存的数据,并可能一起保存为备份与工作副本。就像这样:

$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","" 
... 
3

我想监控安装关键服务在使用PowerShell脚本的服务器上。

因为这似乎是你的动机做这一切的脚本,我要告诉你一个更好的方式来监控服务比写时间戳到一个文件:

  • 打开查看本地服务从开始菜单。
  • 打开要监视
  • 恢复选项卡服务,设立了第一,第二和随后的失败的选项根据自己的喜好的属性窗口。您可以选择重新启动失败的服务,甚至运行程序。您可以像这样运行PowerShell脚本:输入PowerShell作为程序,输入c:\path\to\your\script.ps1作为参数。
  • 在该脚本中,您可以简单地检查当前哪些重要服务未运行。
+0

虽然这是比OP更直接和更好的解决方案来监视服务,但它并没有回答这个问题。 – Clijsters

+0

严格回答这个问题对OP来说是一种伤害,如果这是一个更好的方式来实现他的'我想监视关键服务'的目标。 – Swonkie

+0

当然,只是说。我个人同意你的观点,并且喜欢你的答案,但据我所知,其他人看到这个不同。 – Clijsters

-1

好了,你的榜样......

$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. 在单个管道中获取和设置同一文件的内容很可能会导致冲突。在两条不同的路线上进行操作最简单。

一个固定的版本可能是这个样子:

$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 

附: [正则表达式] :: Escape部分是为了防止ServiceName中有特殊字符...
此外,此脚本不会在最后两行执行时间段内保持文件锁定,所以其他一些应用程序可能会在之间进行更新。使用文本文件,最后一位作者会获胜,所以如果发生冲突,某些更新可能会丢失。

相关问题