PowerShell – Windows-järjestelmän virhelokit automaattisesti .CSV-tiedostoihin

Harjoituksessa käytetty laitteisto/ohjelmisto:

  • Tietokone (Asus Z170-A, i7-6700K , 16GB DDR4 3200MHz, Evga 1070 sc)
  • Oheishärpäkkeet
  • Windows 10 Pro 64-Bit ( versio 1607)
  • PowerShell versio 5.1.14393.1358

Johdanto:

Ensimmäisenä PowerShell harjoituksenani halusin viedä hyödyllisiä merkintöjä Windowsin tapahtumienvalvonnasta helposti luettavaan ja muokattavaan tiedostoformaattiin. Kaikki järjestelmän virheet, varoitukset ja kriittiset tapahtumat otettaisiin automaattisesti talteen toivottuun hakemistosijaintiin. Skripti ajettaisiin Windowsin toimesta viikottain.
Skripti löytyy:
https://github.com/PyhaMarkus/EventLogsToCSV


Testaa SystemLogs kansion olemassaolo:

Tapahtumalokit tallennetaan .csv tiedostoihin oletushakemistoon C:\Users\Markus\Desktop\SystemLogs\. Skriptin ensimmäisenä tehtävä on tarkistaa, onko kyseinen hakemisto olemassa. Se luo SystemLogs kansion, jos sitä ei löydy.

#Check whether a folder named SystemLogs exists. If it doesn't, then create one.
$Path = "C:\Users\Markus\Desktop\SystemLogs\"
    If(!(Test-Path $Path)) {
         New-Item -ItemType Directory -Force -Path $Path
    }

$Path -muuttuja kertoo, minkä hakemiston olemassaoloa testataan.
Test-Path -cmdlet palauttaa arvon “True”, jos hakemistosijainti löytyy ja “False”, jos ei:
true
Tässä tapauksessa haluankin toteuttaa If-lauseen ikäänkuin käänteisesti, eli “Jos $Path hakemistoa ei löydy, luo $Path.

If(!(Test-Path $Path)) {}

Ylläoleva komento on sama, kuin:

If(-not(Test-Path $Path)) {}

Tuossa siis testataan, jos hakemistoa ei löydy, jotta se voidaan luoda. Jos se löytyy, mitään ei tehdä.
Koska tein sen -not “operaattorilla” (operator) käänteiseksi, hakemiston löytyminen tuottaisi tuloksen “False“, jolloin If-lause ei pidä paikkaansa. Mitään ei siis tehdä.
New-Item -cmdlet:llä luodaan hakemisto, jos If-lause pitää paikkaansa, eli saa arvon “True“.

-Force -parametri pakottaa muutoksen huolimatta siitä, onko kohde esimerkiksi “Vain lukutilassa” -tilassa. Ei välttämättä tarpeellinen, jos käyttöoikeudet kunnossa.

-Path -parametrin arvo määrittelee hakemistosijainnin, joka on tässä tapauksessa määritelty muutujalla $Path.


Muuttujat:
#Variables
    #Diretory paths for .csv files.
    $PathError = "C:\Users\Markus\Desktop\SystemLogs\ErrorLogs.csv"
    $PathWarning = "C:\Users\Markus\Desktop\SystemLogs\WarningLogs.csv"
    $PathCritical = "C:\Users\Markus\Desktop\SystemLogs\CriticalLogs.csv"
    #Today's date.
    $Today = Get-Date
    #From how many days are the logs needed. 7 days by default.
    $StartDate = $Today.AddDays(-7)

$PathError, $PathWarning ja $PathCritical muuttujat määrittelevät mihin hakemistosijaintiin ja minkä nimiseen tiedostoon lokitiedot halutaan.
$ Today hakee tämän päivän päivämäärän.
$ StartDate määrittelee moneltako päivältä ennen tätä päivää lokitiedot haetaan. .AddDays metodilla annoin negatiivisen arvon, koska haluan lokitietoja tätä päivää edeltävältä ajalta.


Ilmoita käyttäjälle käynnissäolevasta prosessista:

Write-Host -cmdletillä pystyn kirjoittamaan viestejä PowerShell komentokehotteeseen. Näin ollen olisi kiva tehdä käyttäjälle selväksi, että taustalla oikeasti tapahtuu jotain.

#Notify user that the process is in progress.
Write-Host "Exporting systemlogs to .csv`n..."

`n tarkoittaa rivinvaihtoa. Sitä käytettäessä tulee laittaa lainausmerkit, eikä yksittäisiä heittomerkkejä.
Tulostus näyttää tältä:
tulostus
Skriptin lopussa ilmoitan sitten, että prosessi on valmis.


System lokitietojen haku ja vienti .csv tiedostoon:

WordPress ei ainakaan omalla teemallani näytä koodia kovinkaan selkeästi. Kannattaakin siten katsoa mielummin GitHubista: https://github.com/PyhaMarkus/EventLogsToCSV
ErrorLogs:
Tässä haetaan 100 uusinta error-merkintää tietokoneen System-lokeista $StartDate -muuttujan määrittelemältä ajalta.

#ErrorLogs
     #Get the newest 100 error entries of the system's eventlogs and export results to a .csv file.
     Get-EventLog -LogName System -ComputerName Make-PC -Newest 100 -After $StartDate -EntryType Error |
     Select-Object EventID, TimeGenerated, EntryType, Source, Message |
     Export-Csv -NoTypeInformation $PathError -Delimiter ";" -Encoding UTF8

Get-EventLog -cmdlet hakee tässä yhteydessä paikallisen tietokoneen tapahtumalokit Windowsin Tapahtumienvalvonnasta.

-LogName -parametri voi olla esimerkiksi System tai Application. Se viittaa Tapahtumienvalvonnan lokinimeen:

lokinimi

ComputerName -parametrin string arvo on sen paikallisen tietokoneen nimi. Tässä tapauksessa Make-PC.

Newest -parametrille annetaan lukuarvo. Yllä se on 100, eli Get-EventLog -cmdlet hakee maksimissaan 100 uusinta merkintää lokeista, huolimatta siitä, onko niitä enemmänkin.

-After -parametri viittaa tiettyyn aikaan, eli minkä ajan jäljeltä merkintöjä haetaan. Aika oli skriptissä määritelty muuttujalla $Start-Date.

-EntryType -parametri määrittelee mitä merkintöjä lokitiedoista haetaan. Arvona voi olla esimerkiksi error tai warning. Molemmatkin voi ottaa samaan aikaan:

 -Entrytype Error, Warning

Select-Object -cmdlet antaa minun karsia objekteja lokien tuloksista, tai pikemminkin valita ne, mitkä haluan näytettäväksi.
Export-Csv -cmdlet vie tässä tapauksessa Get-EventLog:in tulokset toivottuun $PathError hakemistosijaintiin .csv-tiedostona.

-NoTypeInformation -parametrin kanssa .csv näyttää tältä:

no notype

Ilman sitä:

withnotype

Sillä siis saa tuon turhan ensimmäisen rivin suodatettua pois.

-Delimeter “;” -parametri tarvitaan, sillä ilman sitä Excel tunkee kaikki objektit samaan sarakkeeseen. Huomasin, että Google Docs osaa kyllä laittaa tiedot omiin sarakkeihinsa ilman tuota, mutta ainakin Excelin kanssa se tarvitaan.

-Encoding UTF8 tarvitaan, jos halutaan ääkköset toimimaan .csv-tiedostoissa.

WarningLogs:
Tässä haetaan 100 uusinta warning-merkintää tietokoneen System-lokeista $StartDate -muuttujan määrittelemältä ajalta.
Kyseinen pätkä toimii täsmälleen samalla periaatteella, kuten ErrorLogs kohdalla.

#WarningLogs
     #Get the newest 100 error entries of the system's eventlogs and export results to a .csv file.
     Get-EventLog -LogName System -ComputerName Make-PC -Newest 100 -After $StartDate -EntryType Warning |
     Select-Object EventID, TimeGenerated, EntryType, Source, Message |
     Export-Csv -NoTypeInformation $PathWarning -Delimiter ";" -Encoding UTF8

CriticalLogs:
Tässä haetaan 100 uusinta critical-merkintää tietokoneen System-lokeista $StartDate -muuttujan määrittelemältä ajalta.
Get-EventLog cmdlet- ei tue critical-merkintöjen hakua Windowsin Tapahtumienvalvonnasta. Siitä syystä jouduin käyttämään Get-WinEvent cmdlettiä.

#CriticalLogs
     #Get the newest 100 critical entries of the system's eventlogs and export results to a .csv file.
     #Note: Level=1; = Critical, Level=2; = Error, Level=3; = Warning
     Get-WinEvent -FilterHashtable @{LogName="System"; Level=1; StartTime=$StartDate;} -MaxEvents 100 |
     Select-Object Id, TimeCreated, ProviderName, LevelDisplayName, Message |
     Export-Csv -NoTypeInformation $PathCritical -Delimiter ";" -Encoding UTF8

Get-WinEvent -cmdlet toimii käytännössä samalla tavalla, kun Get-EventLog, mutta se on uudempi ja joustavampi. Lisäksi sen pitäisi olla paljon tehokkaampi varsinkin, kun haetaan lokeja etätietokoneelta/koneilta. Get-EventLog on aika legacy kamaa, mutta itse tykkäsin sen selkeämmästä syntaksista, ja siksi aloitinkin sillä. Molemmat kuitenkin kelpaavat tarkoitukseeni.

-FilterHashTable -parametri käyttää hash taulukkoa filterinä. Taulukko muodostuu key ja value pareista, kuten alla oelvasta esimerkistä näkyy:

keyname

Esimerkiksi omassa skriptissäni Key name “LogName”:lle on annettu arvo “System”.

Level=1; tarkoittaa kriittistä (critical) tapahtumaa. Vaihtoehtoisesti:

Level=2; tarkoittaa virhettä (error) ja

Level=3; tarkoittaa varoitusta (warning).

-FilterHashTable on selitetty paremmin tässä artikkelissa: https://blogs.technet.microsoft.com/heyscriptingguy/2014/06/03/use-filterhashtable-to-filter-event-log-with-powershell/

-MaxEvents -parametrillä ilmoitetaan montako merkintää lokista haetaan maksimissaan. -Newest ei toimi Get-WinEventin kanssa, mutta -MaxEvents hakee ne merkinnät myös automaattisesti ns. “uusin ensin” järjestyksessä.

Select-Object -cmdlet toimii tässä aivan samalla tavalla, kun Get-EventLog:in kanssa. Tiettyjä objekteja kutsutaan vaan eri nimillä.
Esimerkiksi Source = LevelDisplayName.
Muut parametrit ja cmdletit toimivat myös samalla tyylillä, kun Get-EventLog:in kohdalla.


Ilmoita käyttäjälle, että prosessi on valmis.

Kun lokitiedot on haettu ja viety niille tarkoitettuihin .csv-tiedostoihin, voidaan kertoa, että kaikki on valmista.

#Notify user that the process is done.
Write-Host 'All done!'

Skripti on nyt valmis ajettavaksi.


Skriptin ajo:

Skripti ajetaan PowerShell -komentokehotteessa kutsumalla sitä hakemistosijainnin perusteella. ExecutionPolicyn täytyy sallia skriptien ajaminen ks. https://markuspyharanta.wordpress.com/2017/05/24/windows-10-ensikosketus-powershelliin/

PS C:\Users\Markus> C:\Users\Markus\Desktop\EventLogsToCSV.ps1

PowerShell huomauttaa, ettei rivin 55 mukaista tapahtumaa löydy. Tämä pitääkin paikkansa, sillä tapahtumalokeista ei löydy yhtään kriittistä virhettä viimeisten seitsemän päivän ajalta.
error
Skripti kuitenkin toimii kuten tarkoitettu. Kansiosta SystemLogs löytyy seuraavat tiedostot:
kansio
Tiedosto CriticalLogs onkin kuitenkin tyhjä, koska lokitietoja ei sen kohdalta löytynyt. Jos kuitenkin muokkaisin skriptin hakemaan lokitiedot esimerkiksi viime vuoden ajalta:

#From how many days are the logs needed. 7 days by default.
$StartDate = $Today.AddDays(-365)

Nyt PowerShell ei valita mitään ja kriittisiä tapahtumia löytyykin:
toimi
Tulokset Excelissä:
criticalevents

Yksi skriptin ensimmäisistä tehtävistä oli tarkistaa löytyykö SystemLogs -kansiota, johon .csv-tiedostot tallennetaan. Tämäkin oli helppo testata poistamalla koko kansio koneelta ja ajamalla sitten skripti uudelleen:
createfile
Kansio luotiin uudelleen ja .csv-tiedostot löytyvät sieltä:
logs


Jatkokehitysehdotukset:

Jossain vaiheessa voisi selvittää, miten taulukoiden formaattia voisi muuttaa jo itse skriptissä. Sarakkeiden otsikot voisi esimerkiksi värjätä ja niille määritellä oletusleveyden, ettei tarvitse itse aina laajentaa tiettyä saraketta suuremmaksi.


Skriptin ajamisen automatisointi (Windows 10):

Skriptin automatisointiin on kaksi tapaa:

  • Windowsin Tehtävien ajoitus
  • PowerShell

Käsittelen tässä raportissa kuitenkin ainoastaan tuon ensimmäisen tavan.
Windowsin Tehtävien ajoitus:
1. Kirjoita Windowsin aloitusvalikon hakuun “Tehtävien ajoitus” ja avaa se.
tehtävienajoitus
2. Paina “Luo perustehtävä“. Anna tehtävälle nimi ja kuvaus siitä, mitä se tekee.
kuvaus
3. Ajoita tehtävän suorittaminen. Itse haluan ajaa skriptin viikottain.
ajoitus
4. Anna tarkka ajankohta tehtävän suorittamiselle. Itse haluan ajaa skriptin joka viikon sunnuntaina kello 23.00 aina 9.7.2017 lähtien.
tarkkajaoitus
5. Valitse tehtävän toiminto. Haluan ajaa PowerShell skriptin, joten valitsin “Käynnistä ohjelma“.
toiminto
6. Valitse suoritettava ohjelma. Itse halusin PowerShellin ajavan skriptin, joten kirjoitin seuraavasti:
powershell script
Laitoin siis ohjelman ja argumentit samaan komentosarjaan. Sen toimivuuden voi halutessaan ensin kokeilla painamalla win + r näppäimiä ja syöttämällä komentosarjan siihen.
suorita
7. Aukeaa seuraava ikkuna. Paina “Kyllä“.
kyllä
8. Tarkista tehtävän yhteenveto ja paina “valmis”.
summary
Tehtävä on nyt luotu, ja Windows ajaa skriptin joka sunnuntai.
working
Skripti löytyy kokonaisuudessaan GitHubista:
URL: https://github.com/PyhaMarkus/EventLogsToCSV


Lähteet:

Get-EventLog
URL: https://msdn.microsoft.com/en-us/powershell/reference/5.0/microsoft.powershell.management/get-eventlog
Select-Object
URL: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/select-object
Creating a folder if it does not exist
URL: https://stackoverflow.com/questions/17329443/creating-a-folder-if-it-does-not-exists-item-already-exists
Excel format & -delimeter
URL: https://stackoverflow.com/questions/30219824/using-powershell-to-export-to-csv-with-columns
Export-CSV
URL: https://msdn.microsoft.com/powershell/reference/5.1/microsoft.powershell.utility/Export-Csv
Get-WinEvent
URL: https://msdn.microsoft.com/powershell/reference/5.1/microsoft.powershell.diagnostics/Get-WinEvent
Get-WinEvent example
URL: https://stackoverflow.com/questions/19017338/powershell-get-eventlog-takes-too-long-to-complete
Get-WinEvent Filtering
URL: https://blog.netwrix.com/2015/04/29/advanced-event-log-filtering-using-powershell/
FilterHashTable
URL: https://blogs.technet.microsoft.com/heyscriptingguy/2014/06/03/use-filterhashtable-to-filter-event-log-with-powershell/
Scheduled tasks
URL: https://blogs.technet.microsoft.com/heyscriptingguy/2012/08/11/weekend-scripter-use-the-windows-task-scheduler-to-run-a-windows-powershell-script/
Get-WinEvent vs. Get-EventLog
URL: https://www.mcbsys.com/blog/2011/04/powershell-get-winevent-vs-get-eventlog/


TÄTÄ DOKUMENTTIA SAA KOPIOIDA JA MUOKATA GNU GENERAL PUBLIC LICENSE (VERSIO 3 TAI UUDEMPI) MUKAISESTI. HTTP://WWW.GNU.ORG/LICENSES/GPL.HTML
MARKUS PYHÄRANTA

 

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top