Windows Powershell – The Basics 5
Welkom bij Windows Powershell – The Basics 5! En hoewel we de basic ondertussen echt achter ons gelaten hebben gaan we toch nog even verder met dezelfde titel. In deze post gaan we namelijk voor het eerst aan de slag met Powershell en systeemprocessen, services, lijsten etc. Much to learn… and so little time. Hop hop:
Het allermakkelijkste commando van deze post is het commando om alle actieve processen te bekijken. Dit is namelijk het “Get-Process” commando:
Get-Process |
Het nadeel is dat alle processen snel voorbij scrollen. Dit is dus een goed moment om de output van het scherm op te laten slaan in een bestand / log welke we rustig kunnen raadplegen. Dit doen we met het pijltje “>”. Na het haakje specificeren we de locatie waar het bestand opgeslagen moet worden alsmede de naam van het logbestand:
Get-Process > C:\log.txt |
Het enkele haakje openen overschrijft het bestand als er al een bestand aanwezig is. Als er dus al een bestand bestaat wordt deze overschreven door de nieuwe informatie. Mocht je informatie willen toevoegen aan het bestand dan gebruik je een dubbel pijltje “>>”:
Get-Process >> C:\log.txt |
Bovenstaande methode is de “native” methode bekend van het werken in CMD. Powershell kent hiervoor ook een eigen Cmdlet genaamt “Out-File” welke we middels een pipe kunnen aanroepen. Dan krijgen we dus:
Get-Process | Out-File C:\log.txt |
We kunnen de logfile ook bekijken in Powershell met het “Get-Content” commando:
Get-Content C:\log.txt |
Later in dit hoofdstuk kijken we wat beter naar het Get-Content commando alsmede het werken met tekstbestanden.
Als we alle processen bekijken in het logbestand dan zien we dat een process bestaat uit:
- Naam = ProcessName
- ID (wordt vaak naar gerefereerd als Process ID ofwel PID) = Id
Bovenstaande waardes zijn uniek per proces en hiermee kunnen we dus ook specifieke processen aanroepen. We zien in het overzicht nog meer waardes zoals:
- Handles – Aantal geopende handles
- NPM(K) – Gebruikte Non-Paged Memory in Kilobytes
- PM(K) – Gebruikte Pageable Memory in Kilobytes
- WS(K) – Gebruikte Working Sets van het proces in Kilobytes
- CPU(s) – Processortijd in seconde welke het proces van alle processoren tezamen gevraagd heeft
- SI – Session ID. Processen die met de fysieke computer verbonden zijn hebben altijd Sessie ID 0 en processen die met een remote computer verbonden zijn hebben altijd Sessie ID 1
Als je de exacte naam van het proces weet dan kun je informatie over deze processen gericht opvragen met Get-Process. Bijvoorbeeld:
Get-Process -id 57164 |
of:
Get-Process -ProcessName cmd |
I.p.v. “ProcessName” kunnen we bovenstaande commando korter maken door “ProcessName” te vervangen voor “Name” of zelfs door niets:
Get-Process cmd |
Ook hierin kunnen we wildcards gebruiken. Laten we zeggen dat we alle processen willen zien met HP in de naam, dan gebruiken we:
Get-Process -Name *HP* |
Ook kunnen we proceswaardes koppelen met een komma. Laten we zeggen dat we alle processen met HP, Canon en Brother in de naam willen zien:
Get-Process -Name *HP*,*Canon*,*Brother* |
We kunnen ook gemakkelijk bekijken welke bestand het proces gebruikt en met welke versie van het bestand gewerkt wordt. Dit doen we met “FileVersionInfo”. Bijvoorbeeld:
Get-Process cmd -FileVersionInfo |
Het zal vaak voorkomen dat je een proces wilt stoppen of starten. Ook dit kunnen we doen met de -Name of met -id. Het commando welke we hiervoor gebruiken is “Stop-Process“:
Stop-Process -id 57164 |
of
Stop-Process -Name cmd |
Laten we nu alle processen stoppen met “HP” in de naam:
Stop-Process -Name *HP* |
Ook tijdens het werken met processen kunnen we het “Where-Object” commando gebruiken welke we in de vorige post geleerd hebben. Processen hebben namelijk een “responding” parameter welke “true” is zolang het proces goed reageert en dus “false” is wanner het proces vastgelopen is. Om alle vastgelopen processen te zien gebruiken we:
Get-Process | Where-Object -FilterScript {$_.Responding -eq $false} |
We kunnen nu zelfs de output van “unresponsive” processen gebruiken om middels een 3e pipe deze processen te stoppen. Dit doen we dan als volgt:
Get-Process | Where-Object -FilterScript {$_.Responding -eq $false} | Stop-Process |
Misschien willen we alleen remote sessies stoppen van de processen en breiden we het commando uit met een AND statement:
Get-Process | Where-Object -FilterScript {$_.Responding -eq $false -and $_.SessionID -ne 0} | Stop-Process |
Een process starten gaat op een identieke manier als het stoppen van een process, namelijk met “Start-Process“.
Start-Process cmd |
By default kunnen processen uit het Windows pad gestart worden en bestanden in de huidige (actieve) folder. Om een proces in een alternatieve folder te starten moeten we deze specificeren middels de “-WorkingDirectory” flag zoals:
Start-Process custom-process.exe -WorkingDirectory C:\CustomSoftware |
Voor het starten van processen kunnen we diverse waardes meegeven met de “-verb” flag. Om b.v. een proces als administrator te starten gebruiken we:
Start-Process cmd -verb RunAs |
Het openen in een nieuw consolevenster doen we met “-verb open”:
Start-Process cmd -verb open |
Verb’s welke toegepast kunnen worden zijn per bestandstype anders. Een *.exe zal gestart kunnen worden met de Open en RunAs verbs terwijl een *.txt bestand gestart kan worden met de verbs, Open, Print en PrintTo. Om uit te vogelen welke verbs gebruikt kunnen worden moet je via “new-object” een System.Diagnostics.ProcessStartInfo object aanmaken voor het bestand om vervolgens de verbs te bekijken. Laten we de verbs van Powershell eens bekijken:
$CheckPSVerbs = new-object System.Diagnostics.ProcessStartInfo -args PowerShell.exe $CheckPSVerbs.verbs |
Bovenstaande informatie achterhalen we dus door 2 commando’s te gebruiken. In het eerste commando maken we een variabele genaamd “CheckPSVerbs” aan met “new-object System.Diagnostics.ProcessStartInfo -args PowerShell.exe” welke we vervolgens aanroepen incl. de “.verbs” optie. Verbs is een property van het gemaakte Powershell object in de CheckPSVerbs variabele.
Soms kan het weleens voorkomen dat je pas wilt doorgaan nadat een bepaald proces gestopt is. Hiervoor bestaat het “Wait-Process” commando. Laten we het CMD proces eens stoppen en vervolgens wachten tot deze gestopt is alvorens we verder kunnen. Dit gaat als volgt:
Stop-Process cmd Wait-Process cmd |
Laten we eens wachten tot er 2 processen gestopt zijn met de uitzondering dat we maximaal 30 seconde wachten. Als dan de processen nog niet gestopt zijn gaan we gewoon door. Hiervoor bouwen we een 30 seconde timeout in:
Stop-Process cmd, winword Wait-Process cmd, winword -timeout 30 |
Werken met Powershell en Services
Het werken met Windows services is bijna hetzelfde als we hierboven van de processen hebben geleerd. Uiteraard zijn er een paar kleine uitzonderingen en Powershell kennende een paar andere Cmdlet’s. Laten we eens wat services bekijken, stoppen, starten en rebooten:
“Get-Service” geeft ons een overzicht van alle services (running & stopped):
Get-Service |
Als je de status van een specifieke service wilt bekijken dan benoem je specifiek de service of services:
Get-Service Winmgmt, Wsearch |
Ook wildcards kunnen gebruikt worden:
Get-Service *win* |
Het uitsluiten van processen doen we met de “-Exclude” flag:
Get-Service *win* -Exclude Winmgmt |
Services kunnen 3 statussen hebben, namelijk “running”, “stopped” en “stopping”. Zo bekijken we de services die specifiek aan deze statussen voldoen (deze Cmdlet hebben we al vaker gebruikt om te filteren):
Get-Service | Where-Object {$_.Status -eq "Running"} Get-Service | Where-Object {$_.Status -eq "Stopped"} Get-Service | Where-Object {$_.Status -eq "Stopping"} |
De status kan op verschillende manieren starten, namelijk automatisch, manueel of is disabled. Om een service op deze statussen te zetten gebruiken we het “Set-Service” commando:
Set-Service -Name "AppMgmt" -StartupType automatic Set-Service -Name "AppMgmt" -StartupType manual Set-Service -Name "AppMgmt" -StartupType disabled |
Er is nog 1 ander opstarttype en dat is “delayed start” ofwel het automatisch opstarten van de service maar dan later als alle andere services geboot zijn. PowerShell heeft helaas geen feature om deze setting in te stellen met het “Set-Service” commando. Wel kunnen we andere zaken veranderen met het “Set-Service” commando zoals de naam. Dit doen we als volgt:
Set-Service -Name "AppMgmt" -DisplayName "Applicatie Beheer" |
Of de omschrijving:
Set-Service -Name "AppMgmt" -Description "Een duidelijke nieuwe omschrijving." |
Om een process te stoppen gebruiken we de “Stop-Service” Cmdlet (we gebruiken even voor de netheid de “-Name” flag, maar deze is niet verplicht):
Stop-Service -Name "eventlog" |
Een process welke dependencies heeft kunnen we niet zomaar stoppen. Hier moeten we de “-Force” flag voor gebruiken om het proces te stoppen evenals de “-Confirm” flag om de vraag (weet u zeker dat u…) automatisch wilt beantwoorden met “ja”:
Stop-Service -Name "eventlog" -Force -Confirm |
Een proces starten doen we dan als volgt:
Start-Service -Name "eventlog" |
Een reeds draaiend proces resetten doen we met de “Restart-Service” Cmdlet:
Restart-Service cmd |
Sommige services hebben afhankelijkheden. Met andere woorden, deze services zijn afhankelijk van een andere service om te functioneren. Dit noemen we een zogenaamde “Dependencies”. Laten we de services eens bekijken welke bepaalde dependencies hebben:
Get-Service | Where-Object {$_.DependentServices} |
Als we bovenstaande commando uitvoeren zien we wel de services maar niet de dependencies. Om deze te zien moeten we weer gaan werken met een lijst en dat ziet er als volgt uit:
Get-Service | Where-Object {$_.DependentServices} | Format-List -Property Name, DependentServices, @{Label="NoOfDependentServices"; Expression={$_.dependentservices.count}} |
Dat is even andere koek toch! Wat er gebeurt is dat de output van “Get-Service | Where-Object {$_.DependentServices” doorgepiped wordt naar het Format-List commando. Dit commando maakt een lijst met 3 objecten en noemt de service, de dependencies en het aantal dependencies. Het “Format-List” commando bespreken we verderop meer uitgebreid.
Ook kunnen we services bekijken, stoppen en starten op andere computers. De doelcomputer kunnen we specificeren met de “-ComputerName” flag:
Get-Service -ComputerName "MijnServer1" |
Tot zover het werken met services. We gaan nog even aan de slag met het inkijken van bestanden.
Met tekstbestanden kunnen we heel veel doen en we gaan nu een aantal handige Powershell trucs toepassen. Eerder hebben we het gehad over de “Get-Content” Cmdlet. Zoals de benaming al doet vermoeden haalt de “Get-Content” Cmdlet inhoudelijke informatie uit een bestand. Zo kunnen we b.v. prima een tekstbestand bekijken:
Get-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" |
Zoals je ondertussen al weet is de “-Path” toevoeging niet verplicht:
Get-Content "C:\Users\Jarno\Desktop\Tekstbestand.txt" |
Om slechts de eerste 10 regels van het bestand te bekijken kunnen we de “-TotalCount” flag gebruiken:
Get-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" -TotalCount 10 |
Om specifiek de 5e regel uit het bestand te krijgen vragen we de eerste 5 regels van het bestand op welke we in een array opslaan met haakjes(). Vervolgens bekijken we de laatste lijn door toevoeging van het array karakter [-1] wat betekend dat we de laatste regel uit de array willen hebben:
(Get-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" -TotalCount 5)[-1] |
We kunnen de verkregen content ook in een ander bestand plaatsen door de output naar een bestand te sturen:
(Get-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" -TotalCount 5)[-1] > "C:\log.txt" |
Zoals al eerder gezien is dit de oude methode. De nieuwe methode is:
(Get-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" -TotalCount 5)[-1] | Out-File "C:\log.txt" |
I.p.v. Out-File kunnen we ook de “Set-Content” Cmdlet gebruiken:
(Get-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" -TotalCount 5)[-1] | Set-Content "C:\log.txt" |
Om content aan een bestaand bestand toe te voeren en dus niet zoals “Set-Content” te overschrijven gebruik je de “Add-Content” Cmdlet:c
(Get-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" -TotalCount 5)[-1] | Add-Content "C:\log.txt" |
Met deze “xxx-Content” flags kunnen we ook zelf tekst toevoegen aan een bestand middels de “-Value” flag:
Add-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" -Value "Dit is nieuwe tekst om toe te voegen.`rDit is een nieuwe regel" |
Of we voegen in elk tekstbestand op de desktop deze tekst toe:
Add-Content -Path "C:\Users\Jarno\Desktop\*.txt" -Value "Dit is nieuwe tekst om toe te voegen.`rDit is een nieuwe regel" |
Door “Get-Content” en “Set-Content” te combineren kunnen we zelfs teksten zoeken en vervangen. Dit werkt als volgt:
(Get-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" ) | ForEach-Object {$_ -Replace "Written by", "Geschreven door"} | Set-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" |
We slaan de content met Get-Content op in een array. Vervolgens gaan we in de array met “ForEach-Object” elk woordje af en vervangen we “Written By” voor “Geschreven door”. Tenslotte schrijven we de array terug in hetzelfde bestand.
Tenslotte hebben we nog het “Clear-Content” commando. Met dit commando wissen we de content van een bestand (maar blijft het bestand zelf wel staan). Bijvoorbeeld:
Clear-Content -Path "C:\Users\Jarno\Desktop\Tekstbestand.txt" |
Zo kunnen we ook alle contant verwijderen uit alle tekstbestanden op de Desktop:
Clear-Content -Path "C:\Users\Jarno\Desktop\*.txt" |
Door toevoeging van de “-Force” flag overschrijven we zelfs de inhoud van read=only bestanden:
Clear-Content -Path "C:\Users\Jarno\Desktop\*.txt" -Force |
De volgende Cmdlet welke we gaan bekijken is de “Format-List” Cmdlet.
De Format-List Cmdlet formatteert de output van een commando als een lijst met eigenschappen waarin elke eigenschap op een aparte regel wordt weergegeven. Je kunt Format-List gebruiken om alle of alleen de geselecteerde eigenschappen van een object te formatteren en weer te geven als lijst.
Het “Format-List” commando zagen we eerder in deze post:
Get-Service | Where-Object {$_.DependentServices} | Format-List -Property Name, DependentServices, @{Label="NoOfDependentServices"; Expression={$_.dependentservices.count}} |
Maar laten we het verschil eens gemakkelijk weergeven:
Get-Process |
Bovenstaande lijst laat alle processen in een tabel zien. Mooi… maar processen hebben meerdere eigenschappen. Met onderstaande commando wordt de processentabel geformatteerd naar een lijst waarin we de eigenschappen kunnen zien:
Get-Process | Format-List |
Om meerdere properties weer te geven gebruik je de toevoeging van de “-Property” flag:
Get-Process | Format-List -Property * |
Om alleen een lijst te krijgen met de DisplayName van de processen specifiëren we deze ook met de -Property flag.
Get-Service | Format-List -Property DisplayName |
Overigens is de “-Property” flag niet verplicht en kan het commando ook zonder deze flag uitgevoerd worden:
Get-Service | Format-List DisplayName |
Om echt alle eigenschappen van een specifiek process te zien specificeer je het process:
Get-Process winlogon | Format-List -Property * |
Uiteraard kunnen we de lijst weer exporteren naar een logbestand zoals we al eerder geleerd hebben.
Get-Process * | Format-List -Property * | Out-File C:\log.txt |
Een afgeleide van de “Format-List” Cmdlet is de “Format-Hex” Cmdlet waarmee je bepaalde input kunt formatteren naar hexadecimaal formaat. Bijvoorbeeld een eigen tekst:
"Hallo, mijn naam is Jarno" | Format-Hex |
En een bestand gebruiken als input werkt als volgt:
Format-Hex -Path "C:\log.txt" |
Zo… dat was weer een pittige post …. of nie? De volgende post gaan we loopen…. over and over and over again. Tschüss