2017-05-09 261 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中有特殊字符...
此外,此腳本不會在最後兩行執行時間段內保持文件鎖定,所以其他一些應用程序可能會在之間進行更新。使用文本文件,最後一位作者會獲勝,所以如果發生衝突,某些更新可能會丟失。