Nieuw in PowerShell 7
Wat vroeger ondenkbaar was, is nu bedrijfsbeleid: Microsoft brengt opensource-versies van veel van zijn software uit. Dat geldt ook voor PowerShell, waarvan ondertussen versie 7 is verschenen. Dat is tevens de eerste versie die de normale Microsoft-varian
Microsoft heeft PowerShell de afgelopen jaren uitgebouwd tot een van de belangrijkste beheertools voor Windows. Het is des te verbazingwekkender dat het bedrijf grote delen van de broncode ervan onder een opensourcelicentie heeft geplaatst en de verdere ontwikkeling overlaat – uiteraard met eigen deelname – aan een community van toegewijde programmeurs. Die heeft ondertussen versie 7 voltooid en presenteert die als de eerste opensource-editie van PowerShell die alles heeft wat nodig is om Windows PowerShell te vervangen. Die laatste bestaat nog steeds volledig uit Microsoft-code. Reden genoeg om de nieuwe versie eens beter te bekijken.
GESCHIEDENIS
De technische basis voor PowerShell is altijd het .NET Framework geweest. Sinds 2016 is daar een nieuwe opensource-implementatie van met de naam .NET Core. Vroeg of laat zal die het traditionele .NET Framework vervangen. Een van de opvallende kenmerken van .NET Core buiten dat het opensource is, is de platformonafhankelijkheid. Er zijn momenteel implementaties voor 32- en 64-bit Windows-versies, macOS en diverse Linux-distributies.
In het kader daarvan heeft Microsoft ook grote delen van de PowerShell-code vrijgegeven. Dat heeft geleid tot PowerShell Core, dat is gebaseerd op .NET Core en eveneens platformonafhankelijk is. De toevoeging Core is inmiddels uit de naam verdwenen. Om het te onderscheiden van de closedsource-versie die in Windows zit, noemt Microsoft die versie nu consequent Windows PowerShell. Het huidige versienummer daarvan is 5.1.
Net als bij .NET is het doel bij PowerShell dat de opensourceversie binnenkort de traditionele versie volledig zal vervangen. De laatste stabiele release was versie 6.2, maar versie 7.0 is op het moment dat je dit leest waarschijnlijk al uitgebracht. Voor dit artikel hebben we de RC2 gebruikt omdat de
definitieve versie nog niet ter beschikking stond, maar functionele veranderingen worden niet meer verwacht. PowerShell 7 met het label GA voor General Availability, een stabiele versie die geschikt is voor productiegebruik, zou ondertussen sowieso beschikbaar moeten zijn (die was oorspronkelijk voor eind januari aangekondigd).
We beschrijven hierna vooral hoe PowerShell 7 zich gedraagt op Windows. Maar voor zover de beschreven functies niet expliciet gerelateerd zijn aan de besturingssystemen van Microsoft, is dat ook van toepassing op Linux en macOS.
INSTALLEREN
Installatiepakketten voor PowerShell 7 zijn beschikbaar op de GitHub-pagina's van het project onder Releases (zie de link op de laatste pagina van dit artikel). Het msi-pakket wordt aanbevolen voor gebruik met een normale desktopinstallatie van Windows.
Als je de set-up start door te dubbelklikken op het msi-bestand, suggereert die C:program Files\ PowerShell als installatiemap. Neem die suggestie bij voorkeur over, want dan komt deze PowerShell in een subdirectory van de map terecht die het versienummer als naam heeft. Zo kun je PowerShell 6 en (pre-release-versies van) PowerShell 7 eenvoudig naast elkaar installeren. Het enige wat je in gedachten moet houden, is dat beide de map ~\Documents\PowerShell gebruiken als de standaardlocatie voor scripts. Daardoor draaien ze allebei dezelfde profielscripts die zich daar bij het opstarten kunnen bevinden.
Windows PowerShell wordt op geen enkele manier beïnvloed door het installeren van PowerShell 6 of 7. Er zijn volledig gescheiden moduleen scriptpaden. Zelfs het opnemen van de installatiemap in $env:Path is geen probleem omdat Windows PowerShell begint met het commando powershell en PowerShell Core met pwsh. Als je echter meerdere versies van die laatste wilt, moet je kiezen welke je in het pad opneemt. Alle msi-installaties voegen ook snelkoppelingen met unieke namen toe in het startmenu.
COMPATIBILITEIT
Om te weten te komen hoeveel van de commando's die beschikbaar zijn in Windows PowerShell ook beschikbaar zijn in PowerShell 7, kun je eventueel de items tellen in de submap Modules van een PowerShell 7-installatie. Op ons testsysteem waren dat er slechts 14. Vergeleken met de 79 items in de Modules-map in C:WindowsSystem32\WindowsPowerShell was dat een erg karige verzameling.
Gelukkig is dat een misverstand. Als je de uitvoer bekijkt van het commando Get-Module ListAvailable in beide versies, zijn het er al 74 tegen 86 voor Windows PowerShell. Bij nader inzien blijkt dat PowerShell 7 bijna alle modules van Windows PowerShell makkelijk kan gebruiken. De PowerShell 7-ontwikkelaars schrijven in hun blog dat ze zeer nauw hebben samengewerkt met het Windows-team van Microsoft om dat te laten werken. Volgens hen zijn de meeste modules voor Windows PowerShell opnieuw ontworpen om in beide PowerShell-werelden te werken. Als gebruiker kun je daar echter alleen van profiteren als je Windows 10 of Server 2019 gebruikt, omdat die up-to-date gehouden worden.
Maar zelfs de commando's van Windows PowerShell-modules die nog niet in beide werelden werken – omdat Microsoft ze nog niet heeft aangepast of omdat er een oudere versie van Windows wordt gebruikt – kun je gebruiken in PowerShell 7. Wanneer je zo'n cmdlet aanroept, wordt op de achtergrond Windows PowerShell gestart en wordt het commando doorgegeven via lokale remoting – een soort procedureaanroep op afstand. Het proces is volledig transparant vanuit het perspectief van de gebruiker. Als gevolg daarvan kun je met PowerShell 7 vrijwel elke cmdlet en functie enzovoort gebruiken die je kent van Windows PowerShell.
De enige uitzondering die we hebben gevonden, en die waarschijnlijk grote impact kan hebben op bestaande scripts, zijn de cmdlets die te maken hebben met WMI: Get-WMIObject en dergelijke ontbreken. Ze worden vervangen door commando's die in de CimCmdlets- module zitten, zoals Get-CimInstance,. Die maken al deel uit van Windows PowerShell sinds Windows 8 en Microsoft raadt het gebruik van die commando's al langere tijd aan. Het grootste technische voordeel is dat ze het modernere WinRM-protocol gebruiken in plaats van het verouderde en onveilige DCOM voor remoting, dat wil zeggen WMI-toegang tot andere computers via het netwerk.
De Out-GridView cmdlet en de optie -ShowWindow van het Get-Help- commando zijn daarentegen de nieuwste toevoegingen aan PowerShell 7 op Windows. Beide openen nieuwe vensters op de gebruikersinterface. Dergelijke GUI-interacties zijn pas mogelijk met .NET Core sinds versie 3, en ontbraken daardoor in PowerShell Core tot de laatste release voorafgaand aan versie 7.
Een tool voor scriptontwikkelaars die vergelijkbaar is met de Integrated Scripting Environment
(ISE) in Windows PowerShell is in PowerShell 7 niet beschikbaar. Die leemte wordt opgevuld door de gratis IDE Visual Studio Code, die kan worden uitgebreid met een gratis beschikbare extensie om hem meer dan bruikbaar te maken als ontwikkelomgeving voor PowerShell-scripts.
Op sommige punten overtreffen de capaciteiten zelfs die van de ISE. De debugger biedt bijvoorbeeld voorwaardelijke breakpoints en een controlelijst voor variabelen. De editor controleert de scriptcode al tijdens het invoeren dynamisch op syntaxis en typische programmeerfouten. Visual Studio Code draait op alle systemen waarvoor PowerShell beschikbaar is, inclusief Linux en macOS – zie ook het artikel op pagina 76.
VOORDELEN
Veel kleine details laten zien dat de ontwikkeling van PowerShell 7 gebaseerd is op de dagelijkse ervaringen van gebruikers. Zo zijn de foutmeldingen standaard duidelijker geworden en wordt je niet langer overspoeld met een half venster vol rode tekst. Het oude formaat kan nog steeds worden gebruikt door de waarde 'NormalView' toe te kennen aan de systeemvariabele $ErrorView – standaard is dat 'ConciseView'. Als in specifieke gevallen de compacte foutuitvoer niet voldoende is, is het commando Get-Error beschikbaar: de informatie die dat verschaft gaat zelfs verder dan bij het oude formaat.
De uitvoer van de opdracht Get-ChildItem, of de verkorte vorm hiervan dir, is herzien. Als een map symbolische links of knooppunten bevat, is de linkbestemming direct zichtbaar.
Subjectief gezien voelt het werken met PowerShell 7 vloeiender aan dan met de PowerShell van Windows. We hebben niet veel tijd besteed aan gedetailleerde benchmarks omdat we de definitieve versie nog niet beschikbaar hadden. Maar zelfs de release-candidate voert eenvoudige rekenkundige loops 2 tot 3 keer sneller uit dan Windows PowerShell.
NIEUWE FUNCTIES
In PowerShell 7 bieden zowel de scripttaal zelf als sommige cmdlets mogelijkheden die verder gaan dan die van Windows PowerShell. Je moet echter voorzichtig zijn met de hierna beschreven functies: scripts die er gebruik van maken zullen niet draaien op oudere versies van PowerShell omdat de functies daarin onbekend zijn.
De cmdlet ForEach-Object heeft een nieuwe optie -Parallel vanaf PowerShell 7. Die doet wat je zou verwachten: het volgende scriptblok wordt niet voor elk invoerelement na elkaar uitgevoerd, maar voor meerdere tegelijk. Het aantal threads dat parallel wordt gestart kan worden beperkt met de optie -ThrottleLimit. De standaardinstelling is 5. Het volgende (geheel fictieve) voorbeeld illustreert hoe dat werkt:
1..8 | ForEach-Object - Parallel { Start-Sleep - Milliseconds 500;
"In Thread $_" } - ThrottleLimit 4
De verwerking neemt slechts iets meer dan een seconde in beslag, hoewel het systeem acht keer een halve seconde wacht. Als je dat commando uitprobeert, zul je merken dat de uitvoer van de afzonderlijke threads niet noodzakelijkerwijs in oplopende volgorde verschijnt, maar in willekeurige volgorde kan opduiken binnen groepen van vier. Dat is typisch voor multithread-scenario's. Zelfs de kleinste afwijking in de timing kan grote verschillen in de uitvoering veroorzaken.
Een ander kenmerk van parallelle programma-uitvoering is dat het besturingssysteem in theorie op elk moment de ene thread kan pauzeren ten gunste van een andere. Daarom is bijvoorbeeld de volgende code verkeerd:
$count =0
1..20 | foreach - Parallel {‹
›$ count += 1}
$count
Elke keer dat de lus wordt doorlopen, zou de variabele $count met 1 verhoogd moeten worden. Dat is echter geen op zichzelf staande (atomaire) bewerking: de code moet de oude toestand van de teller uitlezen, er 1 aan toevoegen en het resultaat weer aan de variabele toewijzen. Als een thread na de eerste stap wordt onderbroken en daarna een andere thread wordt uitgevoerd, dan komt de tellerstand bij het optellen al niet overeen met de huidige waarde.
Om te voorkomen dat dit per ongeluk gebeurt, ‘ziet’ een codeblok van foreach -Parallel geen variabelen die erbuiten zijn gedefinieerd, tenzij je ze met de optie using expliciet doorgeeft. Daarom moet je erop letten dat je bij dergelijke variabelen alleen thread-veilige bewerkingen uitvoert. Een
goede implementatie van bovenstaand voorbeeld is dus:
$count =0
$refCount = [ref]$ count 1..20 | foreach - Parallel { [System.Threading.Interlocked]:: Increment($ using: refCount) } $count
De methode [Interlocked]::Increment() hoogt de doorgegeven variabele 1 op in een atomaire, niet onderbreekbare operatie. Dat moet een referentie zijn ([ ref]), oftewel een soort pointer die gebruikt kan worden om de uitgangsvariabele te beschrijven.
SCRIPTTAAL
Als je niet alleen PowerShell-scripts schrijft, maar ook programma's in andere programmeertalen, zul je misschien blij zijn dat je nu de ternaire operator ?: in scripts kunt gebruiken. Met die operator kunnen if-else queries met éénregelige opdrachten iets compacter worden geschreven. Je kunt
$n = 23
if($ n% 2 -eq 0) { 'even' } else { 'oneven' } met de operator ?: schrijven als $n = 23
($ n% 2 -eq 0) ? 'even' : 'oneven'
Het resultaat van het statement kun je desgewenst ook toewijzen aan een variabele of verder gebruiken. Die operator is erg praktisch, maar je moet voorzichtig zijn met het gebruik ervan. Bij lange logische uitdrukkingen die misschien zelfs meerdere niveaus genest zijn, maakt hij een script eerder onoverzichtelijk dan beter leesbaar.
Gebruikers met ervaring in batchprogrammering of het schrijven van Bash-scripts kennen de mogelijkheid om het uitvoeren van een opdracht te laten afhangen van het succes van een eerdere opdracht. Dat is nu ook mogelijk in PowerShell. Bij de regel
Opdracht1 && Opdracht2 wordt Opdracht2 alleen uitgevoerd als Opdracht1
foutvrij is afgewerkt. In tegenstelling daarmee komt bij
Opdracht1 || Opdracht2 alleen Opdracht2 aan bod als Opdracht1 een fout
oplevert.
Soortgelijke mogelijkheden bieden de ‘coalescing’-operators ?? en ?=. De eerste heeft het volgende effect: in de regel
$user = $account ?? 'Administrator' wordt gecontroleerd of de variabele $account de waarde $null of iets anders bevat. In het eerste geval wordt aan $user de waarde ‘Administrator’ toegewezen, anders de inhoud van $account. De operator ??= kan de normale toewijzingsoperator vervangen:
$user ??= 'Administrator'
wijst de opgegeven waarde alleen aan de variabele toe als die op dat moment nog $null bevat, anders blijft de huidige inhoud behouden.
KLEINE TEKORTKOMINGEN
Het onderdeel van PowerShell 7 dat wat ons betreft nog het meest verbeterd moet worden, is de documentatie. De ingebouwde helpfunctie is ook na Update-Help nog onvolledig. Dat kan bij de definitieve release wellicht beter zijn. Maar de helpfunctie van PowerShell 6, die al veel langer de status GA heeft, vertoont hetzelfde manco. De opdracht Get-Help
Daarnaast is PowerShell niet gelokaliseerd en zijn bijvoorbeeld foutmeldingen Engelstalig. Voor veel gebruikers is dat geen probleem en dat is maar goed ook, want we verwachten niet dat er op dat punt binnen afzienbare tijd iets verandert.
CONCLUSIE
Afgezien van de manco’s bij PowerShell 7 qua documentatie en lokalisatie, hebben we geen redenen gevonden waarom het niet productief gebruikt zou kunnen worden. Verschillende nieuwe functies maken het leven van een beheerder zelfs makkelijker.
Hoe lang Windows PowerShell nog zal bestaan is nog onbekend – maar sinds enige tijd wordt bij het opstarten ervan PowerShell (Core) al gepromoot. Vroeg of laat zul je dus moeten overstappen naar die ontwikkeltak. Daarvan is PowerShell 7 de eerste versie waarvoor de ontwikkelaars LTS-ondersteuning hebben aangekondigd. De versies volgden elkaar voorheen nog snel op, maar PowerShell 7 zal ten minste tot december 2022 geüpdatet worden.