Hoe Windows PowerShell je leven makkelijker kan maken

05 juli 2023

Op het eerste gezicht lijkt het niet altijd het meest eenvoudig of gebruiksvriendelijk. Toch is de kans groot dat je, als je iets doet met IT, het wel eens hebt moeten gebruiken: Windows PowerShell. Deze tool die standaard op elke Windows computer aanwezig zijn, is een command line interface (CLI) of kortweg een ‘shell’. Dat wil zeggen, in plaats van een interactieve gebruikersinterface met knoppen, kun je commands intypen om acties uit te voeren op je computer.

Zelf had ik nog heel weinig ervaring met deze tool, totdat ik aan mijn opdracht begon als technisch applicatiebeheerder bij Waterleidingenmaatschappij Drenthe en Waterbedrijf Groningen. Hier werd Powershell veel gebruikt voor het monitoren en onderhouden van alle systemen.

Ik besloot daarom een cursus te volgen om de basics van Powershell te leren. Al gauw had ik de smaak te pakken, en vond ik het zo leuk om te scripten met PowerShell dat het zo’n beetje mijn favoriete bezigheid werd op de opdracht. Ik kwam erachter dat je ongeveer alles wat je op een computer kan doen ook met PowerShell gedaan kan worden, plus nog een stuk meer.

Het grote voordeel van PowerShell is dat je acties geheel automatisch kunt uitvoeren, en ook op meerdere computers tegelijk als je dat zou willen. Het kan je leven als IT’er een stuk gemakkelijker maken en dat is precies de reden waarom Microsoft de tool in 2006 is gaan ontwikkelen. In dit artikel neem ik je mee in hoe je PowerShell gebruikt en wat je er zoal mee kunt.

1. Hoe gebruik je Windows PowerShell (en cmdlets)?

Zoals ik al zei is PowerShell standaard op elke Windows computer geïnstalleerd. Ook op Linux of iOS machines is het te downloaden en te gebruiken, maar daarvoor moet je wel .NET geïnstalleerd hebben op de computer. Dat is namelijk het platform dat wordt gebruikt om de code uit te voeren op je computer, net als bij programmeertalen van Microsoft als C# en Visual Basic.

Als je Windows PowerShell opstart op je computer verschijnt er een locatie, gevolgd door het knipperende balkje waar je commando’s (of kortweg ‘cmdlets’) kunt typen. In PowerShell hebben de cmdlets over het algemeen de volgende structuur: Werkwoord-Zelfstandig naamwoord. Het eerste cmdlet dat je kunt uitproberen is:

Get-ChildItem

Je typt dit in en drukt op Enter om het uit te voeren. Get-ChildItem verkrijgt de bestanden in de locatie. Als je naar een andere locatie wilt navigeren, kun je dat doen met Set-Location. Aan het cmdlet Set-Location moet je tevens een parameter meegeven, namelijk de locatie waar je naartoe wilt:

Set-Location -Path ‘Downloads’

Nu zit je in je downloads map, en wanneer je nog eens Get-ChildItem uitvoert krijg je als het goed is de bestanden in deze locatie. Wil je toch weer een mapje terug? Gebruik dan simpelweg:

Set-Location -Path ..

(1 punt betekent altijd je huidige locatie, twee punten de locatie erboven).

Een ander veelgebruikt cmdlet is Get-Process, deze geeft je informatie over alle processen die op dit moment bezig zijn op je computer. Probeer maar eens!
Zoeken in de lange lijst van processen doe je heel eenvoudig, met de parameter -Name.

Get-Process -Name ‘powershell’

Bij het zoeken kun je tevens de wildcard * gebruiken, wat staat voor: dit kan alles zijn.

Get-Process -Name ‘powersh*’

 Dit is een korte illustratie van hoe PowerShell-cmdlets er in de basis uitzien. Er zijn er werkelijk duizenden, en verderop in dit artikel zal ik nog verschillende anderen introduceren. Als je ergens naar op zoek bent kun je er het beste gewoon op googlen 😉. Voor documentatie over hoe een PowerShell cmdlet werkt, kun je Get-Help gebruiken. Zie bijvoorbeeld:

Get-Help Get-Process –ShowWindow

Zoals je ziet kun je verschillende parameters meegeven aan Get-Process. Onderaan de pagina staat de uitleg van wat deze parameters zijn en wat je er eventueel aan mee kunt geven. Wanneer de parameter tussen vierkante haakjes staat [ ] betekent dat je deze niet uit hoeft te typen.

Get-Process ‘powersh*’

was dus voldoende geweest.

Daarnaast hebben veel cmdlets een alias, dat wil zeggen, een afkorting. In het geval van Get-Process is dat gps, in het geval van Set-Location cd, en Get-ChildItem gci of dir.

gps ‘powersh*’

2. Naar een specifieke property zoeken

Gebruiken van variabele en/of de pipe

Je hebt nu de basis van cmdlets te pakken. Zoals je in de laatste paar voorbeelden hebt gezien krijg je niet 1 gegeven, maar een tabelletje met informatie terug over hetgene dat je opvraagt. Wat je daadwerkelijk terugkrijgt is een object, of een lijst van objecten, en die hebben meerdere properties. Het tabelletje laat vaak niet eens alle properties zien.

Stel nu dat je 1 specifieke property zoekt, bijvoorbeeld de starttijd van het proces. Er zijn dan twee manieren om deze te verkrijgen.

De eerste is door eerst je object te selecteren, en dan van dat object de eigenschap te selecteren met Eigenschap. Dit kun je doen door het object eerst op te slaan in een variabele. Een variabele declareer je met $:

$powershell_process = gps ‘powershell’

Vervolgens selecteer je de eigenschap StartTime:

$powershell_process.StartTime

De tweede manier is om de pipe | te gebruiken. Met de pipe kun je een object doorgeven. Je kunt dan vervolgens nog een cmdlet uitvoeren op de input van de pipe. Zo kun je dus allerlei handige combinaties maken. In dit geval kunnen we het cmdlet Select-Object gebruiken om een property te selecteren van ons object (met de parameter -Property):

gps ‘powershell’ | Select-Object -Property StartTime

Als je wilt weten welke eigenschappen een object allemaal heeft, kan dat door het object door te geven aan Get-Member:

Get-Process | Get-Member

Toepassen van de pipe

Met de pipe kun je dus ontzettend veel combinaties maken. Hier een paar handige voorbeelden:

Cmdlet Omschrijving Voorbeeld(en)
Select-Object
(alias: select)
Selecteer (bepaalde properties van) een object Get-Process ‘powershell’ | Select-Object StartTime

Get-Process | Select-Object -First 3

 

Maak een property door een expressie te bouwen. Dit doe je met curly brackets { }, waarin $_ het doorgegeven object is:
Get-Volume -DriveLetter C | select {$_.Size / 1GB}

 

Geef je property een naam:

Get-Volume -DriveLetter C | select @{name=’Space Used (%)’; expression={100 – ($_.SizeRemaining / $_.Size * 100)}}

 

Met de parameter -ExpandProperty pak je puur de geselecteerde property in plaats van het object met de property:
$last_reboot = Get-CimInstance Win32_OperatingSystem | Select-Object -ExpandProperty LastBootupTime

Write-Output ”Computer laatst herstart op $last_reboot”

Sort-Object
(alias: sort)
Sorteer een lijst met objecten Get-ChildItem | Sort-Object LastWriteTime -Descending
Where-Object
(alias: where / ?)
Filter een lijst met objecten* Get-ChildItem | Where-Object Name -like ‘*.txt’

Get-EventLog -LogName Application | ? {$_.EntryType -eq ‘Error’ -and $_.TimeGenerated -gt (Get-Date).AddDays(-15)}

ForEach-Object
(alias: foreach / %)
Voor een actie uit voor elk van de objecten Get-ChildItem ‘*.txt’ | foreach {Write-Output ”Text file name: $($_.Name)”

$array = @(‘John’, ‘Jack’, ‘James’)
New-Item ‘names.txt’

$array | % {Add-Content ‘names.txt’ $_ }

Format-List
(alias: fl)
Format het resultaat als lijst (tegenhanger van Format-Table (standaardinstelling)) gps powershell | select * | fl

* voor een overzicht van de comparison operators in PowerShell, zie https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators

3. Windows PowerShell ISE

PowerShell onderscheidt zich van andere command-line tools in dat je er naast losse commando’s ook gehele scripts mee kan schrijven. Hiervoor kun je Windows PowerShell ISE gebruiken (deze staat ook standaard op je computer). ISE staat voor Integrated Scripting Environment. In scripts kun je logica gebruiken zoals je dat in andere programmeertalen ook kan: if-else statements, loops, try-catch statements, enzovoorts. Net als bij cmdlets kun je je script parameters laten gebruiken. Met een script kun je dus wat meer logica uitvoeren dan met een los cmdlet. Daarnaast kun je je script opslaan (een PowerShell script is een .ps1-bestand), en deze automatisch / herhaaldelijk uit laten voeren.

4. Meer voorbeelden van wat je kunt doen met PowerShell

Zoals ik al noemde kun je ongeveer alles wat je gewoonlijk op je computer doet ook met Windows PowerShell. Als afsluiting van dit artikel geef ik je een paar voorbeelden, die misschien van pas kunnen komen in je werk. Gebruik hiervoor PowerShell ISE.

$headers = @{

‘Key’ = ‘jouw key (https://www.weatherapi.com/signup.aspx)’

‘Content-Type’ = ‘json’

}

$response = Invoke-WebRequest “https://api.weatherapi.com/v1/current.json?q=Utrecht&aqi=no” -Headers $headers

$weather = $response | ConvertFrom-Json

$weather.location.name

“$($weather.current.temp_c) C°”

$weather.current.condition.text

 

Output (voorbeeld):

Utrecht

11.0 C°

Clear

$connectionString = “Server=server; database=database; Trusted_Connection=True; User ID=username;”

$query = @”

Jouw query

“@

try

{

$sqlConnection = New-Object System.Data.SqlClient.SqlConnection $connectionString

$sqlConnection.Open()

$sqlCmd = New-Object System.Data.SqlClient.SqlCommand

$sqlCmd.Connection = $SqlConnection

$sqlCmd.CommandText = $query

$table = New-Object System.Data.DataTable

$reader = $sqlCmd.ExecuteReader()

$table.Load($reader)

Write-Output $table

$sqlConnection.Close()

}

catch

{

Write-Output “Kan niet verbinden met de database:`n$_”

}

Output is het resultaat van je SQL-query

$objSession =  [activator]::CreateInstance([type]::GetTypeFromProgID(“Microsoft.Update.Session”))

$searchResult = $objSession.CreateUpdateSearcher().Search(“IsInstalled=0″)

$updatesAmt = $searchResult.Updates.Count

$maxSeverity = ”

$totalSize = 0

$updates = for ($i = 0; $i -lt $searchResult.Updates.Count; $i++) {

$totalSize += $searchResult.Updates.Item($i).MaxDownloadSize

$severity = “$($searchResult.Updates.Item($i).MsrcSeverity)”

if ($maxSeverity -eq ”)

{

$maxSeverity = $severity

}

elseif ($maxSeverity -eq ‘Low’ -and ‘Moderate’,’High’,’Critical’ -contains $severity)

{

$maxSeverity = $severity

}

elseif ($maxSeverity -eq ‘Moderate’ -and ‘High’,’Critical’ -contains $severity)

{

$maxSeverity = $severity

}

elseif ($maxSeverity -eq ‘High’ -and $severity -eq ‘Critical’)

{

$maxSeverity = $severity

}

}

$size = ”

if ($totalSize -gt 0) {

$size = [String]([System.Math]::Round($totalSize/1MB, 2)) + ” MB”

}

New-Object PSObject –Property @{

LastUpdated = $lastUpdated

AvailableUpdates = $updatesAmt

Severity = $maxSeverity

Size = $size

}

 

 

Output (voorbeeld):

LastUpdated                              AvailableUpdates        Severity Size

———–                                    —————-                ——– —-

4/30/2023 2:04:36 PM         3                                        747.34 MB

$RAM = Get-CimInstance Win32_PhysicalMemory | Measure -Property Capacity -Sum | %{$_.sum/1Mb}

Get-CimInstance Win32_PerfFormattedData_PerfProc_Process | Select Name, @{name=’Memory(%)’; expression={[math]::Round(($_.WorkingSetPrivate / 1Mb) / $RAM * 100, 2)}} | Sort ‘Memory(%)’ -Descending | select -first 12

Output (voorbeeld):

Name                                       Memory(%)

—-                                            ———

_Total                                      20.46

Memory Compression          4.34

MsMpEng                                1.24

SearchApp                               1.2

chrome                                    0.92

chrome#2                               0.89

powershell_ise                      0.78

WINWORD                            0.59

Code#4                                    0.53

chrome#18                             0.51

Code#2                                    0.43

chrome#6                               0.42

PowerShell-one-liner

Dan is er nog één ander verschil om rekening mee te houden: de PowerShell-one-liner, dat is één doorlopende pijplijn. Maar niet persé een opdracht die zich op 1 fysieke regel bevindt. Want niet alle opdrachten die zich op één fysieke regel bevinden, zijn een one-liner.

Bestaat een uit één onafgebroken pipeline worden . Dat worden one-liners genoemd. Hieronder vind je voorbeelden van Powershell one-liners.

We gaan uit van het volgende voorbeeld; stel, we hebben een csv bestand ‘management.csv’:

$martijn = New-Object PSObject –Property @{

Naam = ‘Martijn Ockers’

Functie = ‘Algemeen Directeur’

Startdatum = ’01-08-2013′

}

$stijn = New-Object PSObject –Property @{

Naam = ‘Stijn Smolders’

Functie = ‘Commercieel Directeur’

Startdatum = ’01-04-2014′

}

$feroz = New-Object PSObject –Property @{

Naam = ‘Feroz Fernandes’

Functie = ‘Manager IT Services’

Startdatum = ’01-11-2016′

}

$management = @($martijn, $stijn, $feroz)

$management | Export-Csv -Path ‘management.csv’ -NoTypeInformation

Gebruik deze cmdlets:

import-csv management.csv | select Naam, @{name=’Startdatum_dt’; expression={[Datetime]::ParseExact($_.Startdatum, ‘dd-MM-yyyy’, $null)}} | Sort-Object Startdatum_dt

En dan krijg je deze output:

Naam                          Startdatum_dt

—-                               —————-

Feroz Fernandes       01/11/2016 12:00:00 AM

Stijn Smolders          01/04/2014 12:00:00 AM

Martijn Ockers         01/08/2013 12:00:00 AM

(Je kunt ongeveer alle datatypen eenvoudig naar elkaar converteren met PowerShell)

Import-Csv ‘management.csv’ | ConvertTo-Json | Out-File ‘management.json’

Als output krijg je naast het bestand management.csv, welke we aan het begin hadden opgemaakt, een nieuwe bestand opgeslagen genaamd management.json.

Get-Service | Select Name, Displayname, Status, StartType | ConvertTo-Html -Head ‘<style>table {border-collapse: collapse; } td, th { border: 1px solid black; text-align: left; padding: 5px; } <style>‘ | Out-file ‘services.html’

Output: het bestand services.html is opgeslagen in je huidige locatie, en kun je openen met elke moderne browser.

(Get-ChildItem -Path .Downloads | ? LastWriteTime -gt (Get-Date -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0)).Count

Output (voorbeeld):

14

Compare-Object -ReferenceObject (Get-Content -Path Testfile1.txt) -DifferenceObject (Get-Content -Path Testfile2.txt)

Output (voorbeeld):

Input Object       SideIndicator
———–              ————-

cat                          =>

racoon                  =>

dog                       <=

squirrel               <=

Get-ChildItem -Path C: -Recurse | ? Name -match ‘log4j’

Output (voorbeeld):

Directory: C:UsersBramPrins.m2repositorylog4jlog4j1.2.12

Mode         LastWriteTime          Length Name

—-             ————-         —— —-

-a—-          9/2/2021   5:03 PM         358085 log4j-1.2.12.jar

-a—-          9/2/2021   5:03 PM             40 log4j-1.2.12.jar.sha1

-a—-          9/2/2021   2:55 PM            145 log4j-1.2.12.pom

-a—-          9/2/2021   2:55 PM            136 log4j-1.2.12.pom.sha1

Invoke-Command -ComputerName computers -ScriptBlock { Get-ChildItem -Path C: -Recurse | ? Name -match ‘log4j’ }

Het laatste nieuws