2017-05-09 17 views
7

Mam plik tekstowy w pewnym miejscu na serwerze. Ten plik zawiera wartość ciągu i znacznik czasu. Chcę zastąpić tę konkretną linię najnowszym znacznikiem czasu przy użyciu PowerShell.Zamień ciąg w pliku tekstowym przy użyciu PowerShell

Poniżej dane plik Notatnika za:

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

Tutaj 09/05/2017 09.1.41 jest MM-dd-rrrr GG-mm-ss i chcę zastąpić ten zgodnie z najnowszymi znak czasu.

Tak więc, jeśli po dwóch minutach powinno być

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

Oto co robię:

$ReplaceString = "$ServiceName + "|" + (Get-Date).ToString('MM-dd-yyyy HH-mm-ss')" 
Get-Content Path -Replace($ServiceName + "|" + $StringLastRunTime,$ReplaceString) | Set-Content Path 

Ale to nie generuje oczekiwany wynik.

UPDATE

Przepraszam za nie jest tak oczywiste wymagania

chcę do monitorowania krytycznych usług zainstalowanych na serwerze za pomocą skryptu PowerShell. Wymieniłem wszystkie usługi, które mają być monitorowane w jednym pliku tekstowym i ta ścieżka została wymieniona w skrypcie. Ten skrypt będzie wykonywany co 5 minut, a jeśli usługa nie zostanie zainstalowana lub usługa zostanie zatrzymana, wygeneruje powiadomienie e-mail. Aby zapobiec powodzeniu wiadomości e-mail, myślę o aktualizacji znacznika czasu z nazwą usługi w pliku tekstowym. Tak więc, jeśli znajdę jedną usługę w trybie zatrzymania lub nie zainstalowałem, wyślę powiadomienie i zaktualizuję sygnaturę czasową ostatniego wysłania. Mam interwał ponownego wysłania, który będzie sprawdzany co pięć minut i jeśli ten interwał zostanie miniony, muszę ponownie wysłać powiadomienie i chcę zaktualizować znacznik czasu.

Code (usunąłem część wysyłania wiadomości e-mail, aby uczynić go mniej skomplikowane):

$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

Jaki jest faktyczny wynik, który jest generowany przez to? – Seth

+0

Czy możesz wkleić cały skrypt? – 30000MONKEYS

+0

@ 30000MONKEYS zaktualizowano –

Odpowiedz

0

Patrząc na kodzie dostarczonego i nie wiedząc, co rzeczywiste wyjście, będę oczekiwać $ReplaceString być źle. Twoje cytaty się nie sumują. To powinno działać na nim:

$ReplaceString = $ServiceName + "|" + (Get-Date).ToString('MM-dd-yyyy HH-mm-ss') 
9

Można to zrobić za pomocą regex:

$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

Proszę wyjaśnić mi część dotyczącą regex –

+0

@RanadipDutta Sprawdź link dodany do odpowiedzi. –

+0

Dzięki .. @ Martin –

0

Kod został dodany do opisu nie wydaje pracować. Ponadto sugeruję użycie operatora formatowania dla łańcuchów.

$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

Mam zaktualizowane pytanie z większym opisem, kodem i przypadkiem użycia –

3

Ponieważ plik jest wykorzystywany jako baza danych, należy zamiast tego użyć przechowywanie CSV opartego, po pierwsze dlatego trzeba cmdlet zaprojektowane do analizowania pliki CSV tam iz powrotem, a mianowicie Import-CSV i Export-CSV, po drugie dlatego, ze CSV jesteś można zapisać informacje o typie kolumn.W ten sposób możesz wygenerować prawidłowy plik CSV jeden raz, a następnie uruchomić Import-CSV, tworząc w ten sposób tablicę z PSObject s, następnie przetwarzasz każdą z nich aktualizując znacznik czasu za pomocą (get-date) lub [DateTime]::Now, następnie zwykłe Export-CSV nadpisuje zapisane dane, z możliwym zapisaniem jako kopię zapasową razem z kopią roboczą. Tak:

$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 

Wcześniej wypełnić plik o następującej treści, zapewniając rzeczywiste nazwy dla usług jesteś targetting do monitora:

"Service","Timestamp" 
"First service","" 
"Second service","" 
... 
3

chcę do monitorowania krytycznych usług zainstalowanych na serwerze za pomocą skryptu PowerShell.

Ponieważ wydaje się być motywację do zrobienia to wszystko włączony, powiem ci lepszy sposób monitorowania usług znaczników czasu niż pisanie do pliku:

  • Otwarte Zobacz usług lokalnych z menu startowego.
  • Otwórz okno właściwości za usługę, którą chcesz monitorować
  • Na karcie naprawy, skonfiguruj opcje dla pierwszego, drugiego i kolejnych awarii do własnych upodobań. Możesz zrestartować awarię usługi, a nawet uruchomić program. Możesz uruchomić skrypt PowerShell w ten sposób: jako parametr wprowadź PowerShell i jako c:\path\to\your\script.ps1.
  • W skrypcie tym można po prostu sprawdzić, które z ważnych usług nie jest aktualnie uruchomione.
+0

Chociaż jest to proste i lepsze rozwiązanie do monitorowania usług niż OP, to nie odpowiada na pytanie. – Clijsters

+0

Bezwzględnie odpowiadając na pytanie jest nieużytkiem dla OP, jeśli jest to lepszy sposób osiągnięcia jego celu "Chcę monitorować najważniejsze usługi". – Swonkie

+0

Pewnie, tylko mówię. Osobiście zgadzam się z tobą i podoba mi się twoja odpowiedź, ale jak wiem, inni widzą to inaczej. – Clijsters

-1

OK, więc Twój przykład ...

$ReplaceString = "$ServiceName + "|" + (Get-Date).ToString('MM-dd-yyyy HH-mm-ss')" 
Get-Content Path -Replace($ServiceName + "|" + $StringLastRunTime,$ReplaceString) | Set-Content Path 

prawdopodobnie może być ustalona.

  1. Ciąg szukasz z -replace musi być regex. Znak | jest wyjątkowy w wyrażeniu regularnym i musi zostać zmieniony. Kompilowałem wyrażenie na osobnej linii i zapisałem je w zmiennej o nazwie $ regex, więc nie zapomnę.

  2. Chcesz uruchomić zamiennik dla każdej linii wychodzącej z Get-Content, więc trzeba to zrobić w oddzielnym kroku, używając% (skrót od "foreach-object").

  3. Użyłbym interpolacji ciągów do utworzenia ciągów. To opcjonalne, ale pokażę, co mam na myśli ...

  4. Przypuszczam, że Path powinna być zmienną, a nie literalną nazwą pliku.

  5. Pobieranie i ustawianie zawartości tego samego pliku w jednym potoku może powodować konflikt. Wykonanie go na dwóch różnych liniach jest najłatwiejsze.

Stały wersja może wyglądać tak:

$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 

PS: Część [regex] :: Escape znajduje się na wypadek, gdyby ServiceName zawierała w niej specjalne znaki ...
Ponadto ten skrypt nie blokuje pliku podczas okresu między dwoma ostatnimi liniami, więc inna aplikacja może zaktualizować go pomiędzy. W przypadku plików tekstowych wygrywa ostatni autor, więc w przypadku kolizji niektóre aktualizacje mogą zostać utracone.

Powiązane problemy