PowerShell en Regex: Een uitgebreide handleiding

Het begrijpen van reguliere expressies (regex) kan voor ons mensen een uitdaging zijn, maar regex kan een ongelooflijk krachtige manier zijn om met teksten te werken. In dit artikel ga je de basisbeginselen leren van werken met PowerShell en Regex.

Je krijgt een introductie tot handige cmdlets zoals Select-String, leert over regex-capturegroepen en maakt kennis met verschillende regex-analysetechnieken.

Vereisten

  • A Windows 7 or later machine running PowerShell 5.1+. This article will be using PowerShell 7.1.0.

Overeenkomst van eenvoudige tekst met Select-String

Om PowerShell en regex samen te demonstreren, is het altijd het beste om door een daadwerkelijk voorbeeld te lopen.

Stel je voor dat je gegevens verzamelt van oudere machines over hun hardware en, met behulp van het wmic-hulpprogramma, een eenvoudig tekstbestand zoals hieronder maakt. We noemen het computername.txt.

BiosCharacteristics={7,11,12,15,16,19,20,21,22,23,24,25,27,30,32,33,39,40,42,43}
 BIOSVersion={"ACRSYS - 2","V1.15","INSYDE Corp. - 59040115"}
 BuildNumber=
 Caption=V1.15
 CodeSet=
 CurrentLanguage=
 Description=V1.15
 EmbeddedControllerMajorVersion=1
 EmbeddedControllerMinorVersion=15
 IdentificationCode=
 InstallableLanguages=
 InstallDate=
 LanguageEdition=
 ListOfLanguages=
 Manufacturer=Insyde Corp.
 Name=V1.15
 OtherTargetOS=
 PrimaryBIOS=TRUE
 ReleaseDate=20200826000000.000000+000
 SerialNumber=NXHHYSA4241943017724S00
 SMBIOSBIOSVersion=V1.15
 SMBIOSMajorVersion=3
 SMBIOSMinorVersion=2
 SMBIOSPresent=TRUE
 SoftwareElementID=V1.15
 SoftwareElementState=3
 Status=OK
 SystemBiosMajorVersion=1
 SystemBiosMinorVersion=15
 TargetOperatingSystem=0
 Version=ACRSYS - 2

In dit geval moet je bijvoorbeeld het serienummer van deze computer extraheren. Dit serienummer bevindt zich op de regel SerialNumber=.

In deze situatie wordt Select-String je nieuwe favoriete tool.

Select-String is een PowerShell-cmdlet waarmee je een reguliere expressiepatroon kunt opgeven en een string kunt retourneren die overeenkomt met dat patroon.

Gerelateerd: Hoe PowerShell’s Grep (Select-String) te gebruiken

Aangezien het patroon dat je zoekt in een bestand staat, moet je eerst dat bestand lezen en vervolgens naar een regex-match zoeken. Om dat te doen, geef je een regex-patroon op met de Pattern-parameter en het pad naar het tekstbestand met de Path-parameter.

Select-String -Pattern "SerialNumber" -Path '.\computername.txt'

De Select-String-cmdlet leest het bestand .\computername.txt en probeert een reeks tekens te vinden die overeenkomen met SerialNumber.

PowerShell and Regex : an example output of select-string

Geloof het of niet, maar je gebruikt al Regex. Regex, in zijn eenvoudigste vorm, komt overeen met specifieke tekens. In deze situatie komt het overeen met de letterlijke zin “SerialNumber”.

Waarschijnlijk wil je echter niet die hele regel. Laten we in plaats daarvan beginnen met het bouwen van een script om alleen de gegevens op te halen waar je om geeft.

Select-String-uitvoer is een rijk object

In het vorige voorbeeld gaf Select-String, wat leek op een eenvoudige tekenreeks, maar die uitvoer was eigenlijk veel meer. Select-String geeft niet alleen een tekstovereenkomst terug. De cmdlet retourneert eigenlijk een heel object.

Bijvoorbeeld, geef een regex-patroon op van This (is) om te zoeken in de tekenreeks This is a string. Je kunt hieronder zien dat als je die uitvoer pijpt naar Get-Member, Select-String een Microsoft.PowerShell.Commands.MatchInfo-object retourneert.

select-string "This (is)" -inputobject "This is a String" | get-member
The properties of a select-string operation

Gebruik van Capture Groups

In het vorige voorbeeld, let op het gebruikte regex-patroon (This (is)). Dit patroon bevat een set haakjes. In een reguliere expressie maken die haakjes een capture-groep aan.

Door een zoekterm tussen haakjes te plaatsen, creëert PowerShell een capture-groep. Capture-groepen “vangen” de inhoud van een regex-zoekopdracht op in een variabele.

Merk op dat in het bovenstaande voorbeeld Select-String een eigenschap genaamd Matches oplevert. Deze eigenschap bevat alle regels of waarden van capture-groepen (indien haakjes worden gebruikt) die zijn gevonden.

De waarden van alle capture-groepen zijn te vinden onder de eigenschap Matches.Groups. De groups-eigenschap is een array van objecten, waarbinnen de value-eigenschap de daadwerkelijke gegevens bevat. De groups-array begint bij 0 (met de waarde van de hele regex-match) en neemt toe met elke capture-groep die je specificeert in de regex-term.

Voor het bovenstaande voorbeeld kun je zowel de hele string extraheren met de eigenschap matches, evenals de overeenkomende is-match die je hebt geëxtraheerd:

$match = select-string "This (is)" -inputobject "This is a String"
#deze eigenschap zal overeenkomen met de hele select-string waarde
$match.Matches.groups[0].value
#deze eigenschap zal overeenkomen met de eerste capture-groep
$match.Matches.groups[1].value
the output of a capture group

Het gebruik van Capture-groepen met Patroonovereenkomsten

Het vastleggen van een letterlijke string is redelijk zinloos, zoals het vastleggen van de letterlijke is in This is. Je verkrijgt geen waardevolle gegevens door een string vast te leggen waarvan je de inhoud al kende. Je kunt ook capture-groepen combineren met patroonmatching om alleen de informatie te extraheren waar je om geeft.

Patroon matching gebruikt speciaal gedefinieerde tekens om een reeks tekens te matchen, in plaats van een specifiek teken. Je kunt patroon matching zien als een joker * (zoals in kladblok) op steroïden.

Laten we zeggen dat je alleen het serienummer in de regel SerialNumber=NXHHYSA4241943017724S00 wilt matchen en niet de hele regel. Je wilt elk teken na de SerialNumber= frase vastleggen. Je kunt dat patroon extraheren door het speciale punt . teken te gebruiken, gevolgd door een regex joker * (aangeduid als een Kwantificeerder).

Het punt vertelt regex om elk enkel teken na SerialNumber= te matchen. De * vertelt regex om de . match nul of meer keer te herhalen. Gecombineerd met een capture groep, zal de regex eruit zien als SerialNumber=(.*). Je kunt dit hieronder zien:

$string = "SerialNumber=numberwecareabout1042"
#extraheer het serienummer met behulp van een capture groep
$match = select-string "SerialNumber=(.*)" -inputobject $string
#output het serienummer
$match.matches.groups[1].value
Using Capture Groups to extract important information

Het speciale . teken is slechts een van de vele verschillende patroon match mogelijkheden. Je kunt woorden, tekenreeksen, nummerreeksen en dergelijke matchen. De Regex Referentie categorie op de regexr website (via de zijbalk) is een uitstekende bron voor verschillende regex uitdrukkingen.

A Practical PowerShell Regex Example

Alles bij elkaar genomen, laten we een script creëren dat:

  1. Een lijst van tekstbestanden inneemt (in het voorbeeld, je zult alleen het voorbeeldtekstbestand pakken)
  2. Het doorlopen van de tekstbestanden en het vinden van het serienummer met behulp van SerialNumber=(.*)
  3. Het genereren van een hashtable met een lijst van computernamen en hun bijbehorende serienummers
#Maak een hashtable om de serienummers te bewaren
$serialNumbers = @{}

#Haal alle tekstbestanden op. In dit geval beperk je je tot één tekstbestand
$files = Get-ChildItem "$pwd\computername.txt"

#Vul de hashtable
foreach ($file in $files) {
    #Allereerst haal je dezelfde string op, zoals in het eerste voorbeeld. Deze keer vang je ook de informatie na het label op in een vangroep
    $serialNumber = select-string "SerialNumber=(.*)" $file.FullName
    #Gebruik nu de vangroep om alleen het serienummer te extraheren. Dit wordt gedaan met behulp van de speciale matches eigenschap. We gebruiken ook de bestandsnaam (zonder extensie) als index voor het serienummer
    $serialNumbers[$file.basename] = $serialNumber.matches.groups[1].value
}
#Schrijf de uitvoer van de hashtable naar het scherm
$serialNumbers | format-table

Je kunt het bovenstaande script in actie zien hieronder met behulp van computername.txt:

output of the above code

De Match Operator

Je hebt geleerd hoe je Select-String kunt gebruiken om regex-patronen in tekst te matchen, maar PowerShell heeft ook een paar handige operators die regex ondersteunen.

Een van de meest nuttige en populaire PowerShell-regexoperators is de match– en notmatch-operators. Met deze operators kun je testen of een string een specifiek regex-patroon bevat.

Als de string overeenkomt met het patroon, zal de match-operator een waarheidsgetrouwe waarde retourneren. Zo niet, dan retourneert het een onwaarheidsgetrouwe waarde. Het tegenovergestelde geldt voor de notmatch-operator.

Hieronder zie je een eenvoudig voorbeeld van dit gedrag in actie.

#voorbeeld van het gebruik van een match-parameter
if("my string" -match "string") {
    "string is in my string!"
}

De Split-operator

Als je strings wilt splitsen op een niet-statisch karakter zoals een spatie, een komma of een tab, kun je de split-operator gebruiken. De split-operator voert een regex-match uit op een string en splitst de string vervolgens in één of meer strings.

De split-operator “converteert” een string naar een array van strings gesplitst op een specifiek regex-patroon.

#maak een array van strings gesplitst door het "\"-symbool. Het "\" wordt ontsnapt binnen split omdat het een speciaal karakter is
"somebody\once told me\the world\is going\to roll me" -split ("\\")

ValidatePattern-parametervalidatie

De regex-ondersteuning van PowerShell eindigt niet alleen bij cmdlets en operators; je kunt ook regex-matching integreren in parameters.

Gerelateerd: Alles wat je ooit wilde weten over PowerShell-parameters

Met de ValidatePattern-parametervalidatieattribuut kun je de waarden van stringparameters valideren op basis van een regex-patroon. Deze validatieroutine is handig om in te perken welke invoer een gebruiker kan gebruiken voor de waarde van een parameter.

#voorbeeldvalidatie met behulp van regex. De ValidatePattern in deze functie zal
#alleen kleine of hoofdletters accepteren, evenals spaties.
#het ^ aan het begin van de regex vertegenwoordigt het begin van de string, en $ aan het einde
#vertegenwoordigt het einde van de string (om de *gehele* string te matchen). De +
#betekent dat de string één of meer tekens moet bevatten om geaccepteerd te worden
function alphaOnly {
    param([ValidatePattern('^[a-zA-Z ]+$')][string]$alphaCharacters)
    write-output $alphaCharacters
}
#dit zal slagen
alphaOnly "Hi Mom"
#dit zal mislukken
alphaOnly "Hi Mom!"

Vervangen van tekst met PowerShell en Regex

In de vorige secties heb je een paar verschillende manieren geleerd om patronen te matchen met PowerShell en regex. Je kunt die kennis een stap verder brengen en ook tekst vervangen die PowerShell heeft gevonden.

Een populaire methode om tekst te vervangen met regex is het gebruik van de -replace-operator. De -replace-operator neemt twee argumenten (gescheiden door een komma) en stelt je in staat om regex te gebruiken om een string te vervangen door een vervanging. -replace ondersteunt ook vangroepen, waardoor je een vangroep in de zoekopdracht kunt matchen en de match in de vervanging kunt gebruiken.

Bijvoorbeeld, met behulp van -replace kun je tekst toevoegen aan een serienummer:

$string = "SerialNumber=numberwecareabout1042"
$currentYear = "2020"
#voeg het jaar toe aan het einde van het serienummer
$serialNumber = $string -replace "SerialNumber=(.*)","SerialNumber=`$1-$currentYear"
write-output $serialNumber
Appending text using the -replace operator and capture groups

Merk op dat in het bovenstaande voorbeeld het dollarteken in $1 wordt geëscaped met behulp van een backtick. Anders zou PowerShell dat $1 als een variabele behandelen in plaats van een speciaal regex-teken.

Leer hoe je betere PowerShell Regex schrijft

Al het bovenstaande kan ingewikkeld klinken, en dat is het ook. In feite zijn er veel regex-functies die in het bovenstaande voorbeeld niet worden behandeld. Gelukkig is regex een veelgebruikte methode voor machinaal lezen, en er zijn tal van hulpprogramma’s om te leren hoe je regex effectief kunt gebruiken.

  • RegexOnewordt beschouwd als de facto bron voor het leren van regex. RegexOne introduceert de mogelijkheden van regex op een hapklare en interactieve manier, waardoor je regex kunt leren terwijl je het schrijft. RegexOne is een fantastische bron om te beginnen met het leren hoe regex werkt vanaf het begin
  • Regexris een van de beste tools die er zijn om je regex te valideren en te bouwen. Naast het hebben van een geweldige real-time regex-testtool, bevat regexr ook een spiekbriefje en een fantastische documentatie-engine.
  • Regexstormgebruikt specifiek de .Net-engine om zijn tool aan te drijven. De site heeft niet alle toeters en bellen die sites als Regexr hebben, maar het zal uw reguliere expressie op dezelfde manier nauwkeurig testen als PowerShell doet. Zelfs als u andere tools gebruikt om uw regex op te bouwen, moet u de regex altijd door regexstorm laten lopen om ervoor te zorgen dat PowerShell deze correct analyseert.

Gebruik PowerShell en Regex niet als het niet nodig is!

PowerShell werkt met objecten. PowerShell is gebouwd rond gestructureerde objecten. Objecten met eigenschappen zijn veel eenvoudiger te beheren dan losse tekst waarbij regex in het spel komt.

Gerelateerd: Terug naar de basis: Het begrijpen van PowerShell-objecten

Een van de belangrijkste doelen van PowerShell en ook gestructureerde talen zoals JSON is om regex en tekst parsing overbodig te maken. Menselijke taal is fantastisch voor regex om te ontcijferen, maar over het algemeen is regex iets wat je probeert te vermijden als het gaat om het opslaan of overbrengen van gegevens.

Gerelateerd: REST API’s beheren met PowerShell en JSON

Sommige mensen raken zelfs opgewonden van het gebruik van regex op gestructureerde talen.

Als je een objectgeoriënteerde methode of een gestructureerde taal zoals JSON, XML, etc. kunt gebruiken in plaats van regex, doe het! Ook al kan je bijna alles doen met regex, betekent niet dat je het moet doen!

Verder met Regex

Na het lezen van dit artikel zou je nu een basisbegrip moeten hebben van hoe regex machines helpt bij het parsen en vinden van tekst, zelfs bij het zoeken naar zeer specifieke of gecompliceerde zinnen. Je zou ook de tools moeten hebben om regex te testen, valideren en leren binnen de context van PowerShell.

Als je dat nog niet hebt gedaan, zijn de RegexOne tutorials een fantastische volgende stap. Test je regex-kennis en versterk je string-vaardigheden in PowerShell!

Source:
https://adamtheautomator.com/powershell-regex/