Windows Powershell – The Basics 4
Hallo allemaal. Wat gaaf dat jullie er weer bij zijn om deze post te volgen waarin we wat dieper in Powershell duiken. De basis hebben we in de broekzak en we gaan verder met het register. Maar alvorens we dat gaan doen gaan we eerst kijken naar 2 commando’s die ook toegepast kunnen worden op bestanden en mappen maar welke we niet goed besproken hebben in de vorige post. Deze gaan alweer iets verder dan de basis… en daar zijn jullie nu helemaal klaar voor. Let’s Go!
We beginnen met het Get-Item commando.
Het “Get-Item” commando (of volgens Powershell terminologie “Cmdlet”) maakt het mogelijk om specifieke informatie van een item te achterhalen. Dit item kan van alles zijn zoals een bestand, register sleutel of een map.
Het commando is als volgt opgebouwd. Allereerst maken we een referentie naar een object b.v. een folder. Laten we zeggen dat we een referentie maken naar “C:\Windows”, dan ziet het commando er als volgt uit:
$(Get-Item C:\Windows) |
Bovenstaande commando doet nog helemaal niks. We vertellen Powershell nu dat we een item willen halen uit C:\Windows. Dit is het object. Wat we werkelijk vanuit dit object willen halen schakelen we eraan middels een punt. Het geschakelde commando is dus een referentie.object commando.
Als we dus willen weten wanneer iemand voor het laatst de C:\Windows folder benaderd heeft dan gebruiken we de toevoeging “lastaccesstime”:
$(Get-Item C:\Windows).lastaccesstime |
Hoewel het dollarteken voor het commando verplicht is werkt het in de meeste gevallen ook zonder het dollarteken. Bovenstaande “lastaccesstime” is een van de mogelijke directory opties (properties). Meerdere properties voor een directory zijn o.a.:
- CreationTime (datum dat folder gemaakt is)
- LastWriteTime (datum dat er voor het laatst iets weggeschreven is in de folder
- Parent (de bovenliggende folder)
Alle opties zijn op te vragen met het commando:
(Get-Item C:\Windows) | Get-Member |
Om te weten wat we b.v. vanuit het register kunnen achterhalen gebruiken we:
(Get-Item hkcu:) | Get-Member |
We kunnen b.v. met “subkeycount” alle subsleutels van een object opvragen.
$(Get-Item hkcu:\software).subkeycount |
De opbouw van het volgende commando is weer net een beetje anders. Het volgende commando is namelijk “Where-Object“. De Where-Object Cmdlet stelt je in staat om te filteren binnen de output van een ander Cmdlet.
Een simpel voobeeld. Alle subitems van de C: drive krijgen we met het commando:
Get-ChildItem c:\ |
Maar als we nu alleen de items willen hebben waarbij “program” voorkomt in de naam dan kun je het volgende gebruiken:
Get-ChildItem c:\ | Where-Object {$_.name -like "*program*"} |
Het eerste gedeelte is helemaal hetzelfde. I.p.v. dat de output van “Get-ChildItem c:\” wordt getoond wordt deze gepiped (doorgezet) naar een andere Cmdlet. Dit doen we uiteraard met het pipe symbool (|). Vervolgens gaan we zoeken met “Where-Object” naar alle items waar in de naam “program” in voorkomt. Het woord “program” kan voorkomen in de gehele naam omdat we hier gebruik maken van reguliere expressie. In dit geval gebruiken we een sterretje wat betekenend dat er 1 of meerdere willekeurige karakters voor en na het woord “program” kunnen komen.
Leer hier meer over reguliere expressies.
We zien nog 2 dingen in het commando welke wat nadere uitleg nodig hebben. Namelijk de filter ({$_.name) en de voorwaarde (-like).
De Where-Object filter begint altijd met een bracket { en eindigt altijd met een bracket}. Vervolgens starten we de filter met de filtersoort. In bovenstaande voorbeeld is dat $_.name, en dus de naam. Je kunt filteren op dezelfde properties als we gezien hebben in het vorige commando. Deze properties kunnen we dus opvragen met “(Get-Item C:\Windows) | Get-Member”.
Elk type object heeft weer andere zaken waarop gefilterd kan worden. Zo zullen we bij een systeemproces kunnen filteren op handles maar dit zal niet werken wanneer we iets zoeken binnen de bestandsstructuur omdat bestanden niet met “handles” werken.
Vervolgens moeten we opgeven aan welke voorwaarde de zoekopdracht moet voldoen. Deze voorwaarde geven we aan met een zogenaamde “Powershell Comparison Operator“. Hier kunnen we alle comparison parameters gebruiken.
-eq
Equal / Gelijk aan
-ne
Not equal / Niet gelijk aan
-ge
Greater than or equal / Gelijk aan OF groter
-gt
Greater than / Groter dan
-lt
Less than / Kleiner dan
-le
Less than or equal / Gelijk aan OF kleiner
-like
Wildcard comparison / Vergelijking middels wildcards waarbij de vergelijking “True” is.
-notlike
Wildcard comparison / Vergelijking middels wildcards waarbij de vergelijking “False” is.
-match
Regular expression comparison / Vergelijking middels wildcards waarbij de vergelijking “Exact Match” is.
-notmatch
Regular expression comparison / Vergelijking middels wildcards waarbij de vergelijking “None Exact Match” is.
-replace
Replace operator / Als match, dan vervangen door
-and
Logical And / Waarde moet voldoen aan beide operators
-or
Logical Or / Waarde moet voldoen aan 1 van beide operators
-not OF !
logical not / Als de waarde niet voldoet aan
Het Where-Object Cmdlet kunnen we dus toepassen in veel gevallen. Hier een 3-tal voorbeelden:
1. Bekijk alle folders direct in de C:\ root welke na 01-01-2016 benaderd zijn:
Get-ChildItem c:\ | Where-Object {$_.LastAccessTime -gt "01/01/2016"} |
2. Bekijk alle services die gestopt zijn:
Get-Service | Where-Object {$_.Status -eq 'Stopped'} |
3. Bekijk alle processen die meer dan 200 handles in gebruik houden
Get-Process | Where-Object {$_.handles -ge 200} |
Het format van het commando kan ook afwijken. In onderstaande voorbeeld geven we geen waarde op, alleen een filter en een comparison operator. In dat geval plaatsen we de comparison operator voor de filter:
Bekijk alle bestanden van C:\Apps\ zonder de folders te tonen:
Get-ChildItem 'C:\Apps\' -Recurse | Where-Object {-not $_.PsIsContainer} |
We kunnen ook meerdere voorwaarden gebruiken welke we koppelen met OR of AND:
In onderstaande voorbeeld zoeken we elke folder en elk bestand op binnen de C:\ root welke benaderd is na 01-01-2016 en “system” in de naam hebben.
Get-ChildItem c:\ -recurse | Where-Object {$_.LastAccessTime -gt "01/01/2016" -and $_.name -like "*system*"} |
In onderstaande voorbeeld koppelen we 3 zoekopdrachten. We gaan namelijk zoeken naar bestanden met 2 mogelijke extensies welke benaderd zijn na 01-01-2016:
Get-ChildItem c:\ -recurse | Where-Object {($_.extension -eq ".xls" -or $_.extension -eq ".xlsx") -and ($_.creationtime -ge "01/01/2016")} |
Wat opvalt in bovenstaande Cmdlet is dat zoekvoorwaarde 1 ($_.extension) en zoekvoorwaarde 2 ($_.creationtime) van elkaar gescheiden zijn middels haakjes. Deze haakjes gebruiken we om de leesbaarheid van de Cmdlet te handhaven. De haakjes maken duidelijk inzichtelijk welke zoekvoorwaarden we gebruiken en op welke manier deze gekoppeld zijn. Zonder haakjes werkt de Cmdlet wel maar is de leesbaarheid een stuk onduidelijker. Zie hetzelfde commando zonder haakjes hieronder. Leer jezelf dus aan altijd te groeperen middels haakjes.
Get-ChildItem c:\ -recurse | Where-Object {$_.extension -eq ".xls" -or $_.extension -eq ".xlsx" -and $_.creationtime -ge "01/01/2016"} |
Tussen de haakjes staat de comparison operator. Als we niet de AND maar de OR comparison operator gebruikt hadden dan hadden we alle bestanden teruggekregen welke een XLS of een XLSX extensie hebben evenals alle bestanden en folders die na 01-01-2016 benaderd waren.
De comparison parameter welke we nog niet gebruikt hebben is de XOR. XOR staat bekend als een booleaanse operator en is een “eXclusive OR”. Een XOR resulteert in “true” wanneer 1 van de statements “true” is en de andere “false” is. Wanneer beide statements “true” of “false” zijn dan resulteert de XOR in een “false”. In onderstaande voorbeeld doorzoeken we de C:\ root met een “-force” flag zodat ook verborgen mappen “meedoen”. We zoeken hier met een XOR naar folders welke de naam *program* bevatten of welke *files* bevatten:
Get-ChildItem c:\ -force | Where-Object {$_.name -like "*program*" -or $_.name -like "*files*"} |
Gewone mappen zoals “Windows” vallen met bovenstaande Cmdlet af omdat deze niet voldoen aan de naam “program” of aan “files”. 2x een false is dus false.
Ook “Program Files” en “Program Files(x86)” vallen af. Deze voldoen namelijk aan beide statements. De namen bevatten namelijk zowel “program” als “files”.
Het enige resultaat van deze string zal dus de “ProgramData” folder zijn. Deze voldoet qua naam namelijk maar aan 1 van beide voorwaarden, namelijk aan “program” en niet aan “files”.
Ok… genoeg krom denken voor nu 🙂 We gaan even iets compleet anders doen. We gaan verder werken in het register.
Werken in het Windows Register met Powershell
In de vorige Powershell post zijn we al even heel kort in het register aan het kijken geweest. We gaan nu een paar extra Cmdlets leren om in het register te werken. Even resume:
In onze voorbeelden gebruiken we voor het gemak iedere keer de HKEY_CURRENT_USER ofwel de “hkcu:” hive. Om alle hives en subsleutels te zien welke direct onder deze hive vallen gebruiken we het volgende commando:
Get-ChildItem –Path hkcu: |
Om ook alle verborgen + system items te zien gebruiken we ook hier weer de –force flag:
Get-ChildItem –Path hkcu: -force |
En zoals we ook al geleerd hebben, de –recurse flag zorgt ervoor dat we alle items en alle subitems te zien krijgen (dus de complete hive):
Get-ChildItem –Path hkcu: -recurse |
En we kunnen nog meer reeds geleerde kennis toepassen. Laten we eens filteren binnen een hive met het “where-object” commando. In onderstaande voorbeeld willen we alle sleutels onder de HKCU hive zien welke exact 1 subkey hebben met meer dan 500 waardes:
Get-ChildItem -Path HKCU:\Software -Recurse | Where-Object -FilterScript {($_.SubKeyCount -le 1) -and ($_.ValueCount –gt 500)} |
Het maken van een nieuwe sleutel in het register is simpel. Omdat alle sleutels als het ware containers zijn is het niet nodig om een ItemType op te geven. Een nieuwe sleutel onder de HKCU root maken we als volgt:
New-Item -Path hkcu:\Testsleutel |
Om een sleutel te kopiëren specificeren we de originele sleutel en het doelpad:
Copy-Item -Path hkcu:\AppEvents -Destination hkcu:Testsleutel |
Bovenstaande opdracht kopieert alleen de “AppEvents” sleutel onder de “Testsleutel”. Door toevoeging van de “-recurse” flag worden alle subsleutels en waardes ook gekopieerd:
Copy-Item -Path hkcu:\AppEvents -Destination hkcu:Testsleutel -Recurse |
Het verwijderen van de “AppEvents” sleutel onder de “Testsleutel” gaat als volgt:
Remove-Item -Path hkcu:\Testsleutel\AppEvents |
Als de sleutel welke je wilt verwijderen ook onderliggende sleutels en waardes bevat zal Powershell je vragen of je deze ook wilt verwijderen. Om dit ter voorkomen (en je raad het waarschijnlijk al) moet ook de “-recurse” regel toegepast worden:
Remove-Item -Path hkcu:\Testsleutel\AppEvents -recurse |
Het werken met sleutels is nog relatief gemakkelijk. Sleutels kunnen echter ook waardes bevatten. Laten we eens een sleutel toevoegen. Deze sleutel noemen we uhhhh “sleutel” en het wordt een DWORD type met een waarde van 1. Dit doen we middels het “New-ItemProperty” commando:
New-ItemProperty –path hkcu:\Testsleutel –name "sleutel" –value 0 –PropertyType "DWORD" |
De waarde verwijderen werkt bijna hetzelfde als het verwijderen van een sleutel, echter moeten we hier het pad naar de sleutel en de naam van de waarde opgeven:
Remove-ItemProperty –Path hkcu:\Testsleutel\ –Name "sleutel" |
Om te kopiëren gebruiken we dezelfde truc, dus opgeven van bron sleutel gevolgd door de doel sleutel en doel waarde. De waarde hoeft maar 1x opgegeven te worden omdat deze hetzelfde wordt in de doelmap als in de bronmap:
Copy-ItemProperty –Path hkcu:\Testsleutel\ -destination hkcu:\Classes\ -name sleutel |
Het aanpassen van de waarde van een sleutel werkt weer iets anders. Laten we eerst eens kijken naar de waarde van een sleutel middels het “Get-ItemProperty” commando:
Get-ItemProperty –Path hkcu:\Testsleutel\ -name sleutel |
Zoals al eerder opgegeven is de huidige waarde “0” maar deze gaan we veranderen in 1 met het “Set-ItemProperty” commando:
Set-ItemProperty –Path hkcu:\Testsleutel\ -name sleutel –value 1 |
Werken met sleutels in het register is dus gemakkelijk, dit zijn altijd containers (folders) die naast een naam geen verdure eigenschappen hebben. Werken met waardes is echter wat lastiger. Hou er altijd rekening meer om bij het werken met waardes ook altijd de waarde (-name) in je commando te specificeren. Waardes worden altijd gecontroleerd met “ItemProperty” welke in New, Remove, Copy, Get en Set modus geschakeld kan worden.
Einde deel 4
Hiermee zijn we aan het einde gekomen van deeltje 4. Ik denk dat we ondertussen al aardig geavanceerd kunnen werken met Powershell. Powershell goeroes kunnen dan ook sneller systeemtaken uitvoeren dan menig administrator dat kan met een toetsenbord en muis.
In deel 5 gaan we verder met o.a. systeemprocessen.