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:
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ä:
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:
–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ä:
Ilman sitä:
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:
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.
Skripti kuitenkin toimii kuten tarkoitettu. Kansiosta SystemLogs löytyy seuraavat tiedostot:
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:
Tulokset Excelissä:
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:
Kansio luotiin uudelleen ja .csv-tiedostot löytyvät sieltä:
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.
2. Paina “Luo perustehtävä“. Anna tehtävälle nimi ja kuvaus siitä, mitä se tekee.
3. Ajoita tehtävän suorittaminen. Itse haluan ajaa skriptin viikottain.
4. Anna tarkka ajankohta tehtävän suorittamiselle. Itse haluan ajaa skriptin joka viikon sunnuntaina kello 23.00 aina 9.7.2017 lähtien.
5. Valitse tehtävän toiminto. Haluan ajaa PowerShell skriptin, joten valitsin “Käynnistä ohjelma“.
6. Valitse suoritettava ohjelma. Itse halusin PowerShellin ajavan skriptin, joten kirjoitin seuraavasti:
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.
7. Aukeaa seuraava ikkuna. Paina “Kyllä“.
8. Tarkista tehtävän yhteenveto ja paina “valmis”.
Tehtävä on nyt luotu, ja Windows ajaa skriptin joka sunnuntai.
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