Articles

ForEach en waar magic methods

ForEach en waar zijn twee veelgebruikte concepten die beschikbaar zijn in PowerShell sinds versie 1 kwam in 2006. ForEach is beschikbaar als zowel een statement als een cmdlet( ForEach-Object), zodat u kunt herhalen door middel van een verzameling van objecten en een enkele actie te ondernemen voor elk object in die collectie. Waar is beschikbaar als een cmdlet( Where-Object), waarmee u items in een collectie kunt filteren die niet aan een bepaalde voorwaarde voldoen, een voorwaarde die kan worden geëvalueerd met behulp van de eigenschappen van objecten in de collectie of de objecten zelf die tot de collectie behoren. De ForEach mogelijkheid om actie te ondernemen op items in een collectie en de Where mogelijkheid om een collectie te filteren zijn functies die zeer nuttig zijn en zijn opgenomen in een of andere vorm in de logica achter veel PowerShell scripts, commando ‘ s en modules, ongeacht welke versie van PowerShell wordt gebruikt. In feite worden ze zo intensief gebruikt dat ze een aandachtsgebied zijn geweest voor verbetering van prestaties, functionaliteit en syntaxis in PowerShell-versies 3.0 en 4.0.

met de release van Windows PowerShell 4.0, werden twee nieuwe “magic” methoden geïntroduceerd voor collectietypen die een nieuwe syntaxis bieden voor toegang tot ForEach en waar mogelijkheden in Windows PowerShell. Deze methoden zijn treffend genoemd ForEach en waar. Ik noem deze methoden “magie” omdat ze heel magisch zijn in hoe ze werken in PowerShell. Ze worden niet weergegeven in Get-Member-uitvoer, zelfs niet als je apply-Force en request-MemberType All. Als u uw mouwen oprolt en met reflectie graaft, kunt u ze vinden; echter, het vereist een brede zoekopdracht, omdat ze privé-uitbreidingsmethoden zijn geïmplementeerd op een privé-klasse. Maar ook al zijn ze niet vindbaar zonder gluren onder de covers, ze zijn er wanneer je ze nodig hebt, ze zijn sneller dan hun oudere tegenhangers, en ze bevatten functionaliteit die niet beschikbaar was in hun oudere tegenhangers, vandaar het “magische” gevoel dat ze je achterlaten wanneer je ze gebruikt in PowerShell. Helaas blijven deze methoden nog steeds ongedocumenteerd, zelfs vandaag, bijna een jaar geleden dat ze publiekelijk werden vrijgegeven, dus veel mensen realiseren zich niet de kracht die beschikbaar is in deze methoden. Dit artikel zal proberen dit te corrigeren door uit te leggen waar ze kunnen worden gebruikt en hoe ze werken, zodat je deze magie kunt gebruiken wanneer je PowerShell gebruikt.

een opmerking over PowerShell 3.0

voordat ik ga uitleggen hoe de ForEach en waar methoden werken, moet ik iets vermelden met betrekking tot deze twee methoden en PowerShell 3.0. Hoewel het waar is dat de ForEach en waar methoden werden alleen beschikbaar gesteld in PowerShell 4.0 en latere versies, PowerShell 3.0 wordt nog steeds veel gebruikt in veel omgevingen, en tenzij je PowerShell gebruikt in een omgeving die is gestandaardiseerd op PowerShell 4.0 en later, zou je kunnen wensen dat je zou kunnen profiteren van de syntaxis van de nieuwe methoden bij het gebruik van PowerShell 3.0. Ik vond dit een beperking waard aanpakken, dus als onderdeel van de TypePx module die ik onlangs gepubliceerd op GitHub en in de PowerShell Resource Gallery (aka de PowerShellGet public repository, momenteel in beperkte preview), ik opgenomen ForEach en waar script methoden die functioneel gelijkwaardig zijn aan de methoden die in PowerShell 4.0, zodat u de nieuwe syntaxis en functionaliteit kunnen benutten, zelfs als je gebruik maakt van PowerShell 3.0. Er zijn een paar tekortkomingen in deze uitvoering, die ik later in dit artikel zal benadrukken.

de ForEach methode

ForEach is een methode die u toelaat om snel door een verzameling objecten te herhalen en actie te ondernemen op elk object in die verzameling. Deze methode biedt snellere prestaties dan zijn oudere tegenhangers (de foreach statement en de foreach-Object cmdlet), en het vereenvoudigt ook een aantal van de meest voorkomende acties die u wilt nemen op de objecten in de collectie. Alle objecten die met deze methode worden uitgevoerd, worden geretourneerd in een generieke verzameling van typesystemen.Collectie.ObjectModel.Collectie1.

er zijn zes manieren waarop u deze methode kunt aanroepen, en elk van deze manieren zal hieronder nader worden uitgelegd. De ondersteunde argumenten die kunnen worden gebruikt bij het aanroepen van de ForEach methode zijn als volgt:

  • ForEach(scriptblock expressie)
  • ForEach(type convertToType)
  • ForEach(string propertyName)
  • ForEach(string propertyName, object newValue)
  • ForEach(string methodName)
  • ForEach(string methodName, object argumenten)
  • ForEach(scriptblock expressie, object arguments)

Merk op dat deze worden ondersteund argument paringen, niet anders overbelasting beschikbaar voor de ForEach-methode. Het gebruik van andere argumenten dan deze kan resulteren in fouten die niet duidelijk identificeren wat het werkelijke probleem is.

ForEach(scriptblock expression) en ForEach (scriptblock expression, object arguments)

Als u een scriptblock expression doorgeeft aan de foreach methode, kunt u dezelfde taken uitvoeren als in een scriptblok dat u zou gebruiken met het foreach statement of de foreach-Object cmdlet. Ook, net als de foreach-Object cmdlet, verwijzen de variabelen $_ en $PSItem beide naar het huidige item dat wordt verwerkt. Alle argumenten die u verstrekt buiten het initiële script blok argument zullen worden gebruikt als argumenten voor het script blok. Dit is precies zoals de parameter-ArgumentList werkt op de cmdlet ForEach-Object. Hier is een voorbeeld dat laat zien hoe je dit zou kunnen gebruiken om een scriptblok uit te voeren op elk item in een verzameling:

# Get a set of services$services = Get-Service c*# Display the names and display names of all services in the collection$services.foreach{"$($_.Name) ($($_.DisplayName))"}# Select a property name to expand using a script block argument$services.foreach({param($PropertyName); $_.$PropertyName}, 'DisplayName')

Je hebt misschien iets vreemds gemerkt aan deze syntaxis, omdat ik het scriptblok zelf niet tussen haakjes wikkelde. U kunt het in ronde haakjes wikkelen, maar dat is optioneel in PowerShell 4.0 of later omdat de PowerShell-parser is verbeterd om de haakjes weg te laten wanneer u een methode aanroept die een enkel script blok argument accepteert. Ook, net als de foreach statement en de foreach-Object cmdlet, wordt het script blok dat je opgeeft aangeroepen in de huidige scope. Dat betekent dat elke variabele toewijzingen die je maakt binnen dat script blok zal blijven bestaan nadat de ForEach methode is voltooid uitvoeren.

ForEach (type convertToType)

uniek voor de foreach methode, kunt u een type doorgeven aan de ForEach methode als u elk item in een verzameling wilt converteren naar een ander type. Stel je bijvoorbeeld voor dat je een verzameling objecten hebt en dat je die objecten wilt converteren naar hun string equivalent. Hier is hoe dat eruit zou zien met de ForEach methode:

# Get a collection of processes$processes = Get-Process# Convert the objects in that collection into their string equivalent$processes.foreach()

je had dezelfde taak kunnen uitvoeren door de collectie te typen in een array van type string (bijvoorbeeld ]$processen), en het typen van de array is in feite aanzienlijk sneller, maar er is een zeer goede kans dat je het verschil in uitvoertijd niet eens zou merken tenzij je met een zeer, zeer grote collectie werkt. Ondanks het tijdsverschil, zal ik de voorkeur geven aan de foreach methode syntaxis in bepaalde situaties als het me toestaat om elegantie te behouden in de implementatie door het vermijden van extra ronde haakjes in de scripts die ik schrijf.

ForEach (string propertyName)

in PowerShell 3.0 en later werd een tweede parameterset toegevoegd aan ForEach-Object om u in staat te stellen de waarde van een specifieke eigenschap gemakkelijker op te halen door simpelweg een eigenschapsnaam als enige parameterwaarde voor ForEach-Object door te geven. Dit gemak is aangeboden in de ForEach methode ook. Hier is een voorbeeld dat laat zien hoe je door een verzameling heen kunt itereren en een eigenschap van die verzameling kunt retourneren:

# Get all services whose name starts with "w"$services = Get-Service w*# Return the names of those services$services.foreach('Name')

natuurlijk kun je sinds versie 3.0 van PowerShell gewoon $aanroepen services.Name om de namen van alle diensten te krijgen, en dat zal sneller dan de ForEach methode alternatief (hoewel je alleen de prestaties verschil in zeer grote collecties in de Orde van honderdduizenden objecten merken); echter, dat werkt alleen voor eigenschappen die niet op de collectie zelf, en het is een syntaxis die sommige scripters zijn niet comfortabel met als gevolg van de impliciete aard van wat het commando doet. De nieuwe foreach methode syntaxis biedt u een meer expliciet alternatief dat het extra voordeel van een beetje meer zelf-documenteren en heeft.

ForEach(string propertyName, object newValue)

u kunt niet alleen een eigenschap ophalen op een verzameling objecten, u kunt ook een eigenschap instellen op een verzameling objecten. Dit is functionaliteit die niet beschikbaar is in de andere foreach ‘ s, tenzij je expliciet het script blok om dit te doen. Om de eigenschap in te stellen, geeft u eenvoudig de eigenschapsnaam en de waarde op die u wilt gebruiken bij het instellen van die eigenschap, als volgt:

# Note, this is not a realistic example# This would be used more commonly on configuration data$services = Get-Service c*# Now change the display names of every service to some new value$services.foreach('DisplayName','Hello')

net als toewijzingen die u zou maken met de operator==, PowerShell zal proberen om wat u als de nieuwe waarde opgeeft om te zetten in het juiste type voor de eigenschap die wordt toegewezen.

ForEach(string methodName) en ForEach (string methodName, object arguments)

om een methode aan te roepen, geef je gewoon de method name op als het eerste argument, en dan de argumenten voor die methode als de tweede, derde, vierde, enz. argumenten. Als de methode geen argumenten aanneemt, kunt u gewoon de method-naam doorgeven en deze zal zonder argumenten worden aangeroepen. Hier is een voorbeeld dat laat zien hoe je een aantal processen kan doden die een specifiek programma draaien:

# Get all processes running Chrome$processes = Get-Process -Name Chrome# Now kill all of those processes$processes.foreach('Kill')

Hier is een ander voorbeeld, dit keer met behulp van een methode met argumenten en laat zien hoe u kunt controleren of commando ‘ s de beste praktijken volgen door gebruik te maken van de juiste namen en aliassen voor veelgebruikte parameters:

# Get all commands that have a ComputerName parameter$cmds = Get-Command -ParameterName ComputerName# Now show a table making sure the parameter names and aliases are consistent$cmds.foreach('ResolveParameter','ComputerName') | Format-Table Name,Aliases

zoals u kunt zien aan deze resultaten, zijn er zeker enkele inconsistenties in de implementatie van ComputerName parameters die gecorrigeerd moeten worden.

die alle functionaliteit omvat die momenteel beschikbaar is in de ForEach methode. Zoals je kunt zien, is er niet veel nieuwe functionaliteit aangeboden in deze methode, maar de syntaxis verbeteringen wanneer u het uitvoeren van een eenvoudige taak op een verzameling van objecten zijn leuk, en de ForEach methode prestatieverbeteringen in vergelijking met de gelijkwaardige foreach statement voor ForEach-Object pijplijn zijn zeker een welkome verbetering. Met die uitleg uit de weg, laten we verder gaan met de Where methode.

De Where methode

Where is een methode waarmee u een verzameling objecten kunt filteren. Dit lijkt erg op de waar-Object cmdlet, maar de waar methode is ook als Select-Object en Group-Object als goed, bevat een aantal extra functies die de waar-Object cmdlet niet native ondersteunt op zichzelf. Deze methode biedt snellere prestaties dan Where-Object in een eenvoudige, elegante opdracht. Net als de ForEach methode, worden alle objecten die met deze methode worden uitgevoerd geretourneerd in een generieke verzameling van type systeem.Collectie.ObjectModel.Collectie1.

er is slechts één versie van deze methode, die als volgt kan worden beschreven:

Where(scriptblock expression])

zoals aangegeven door de vierkante haakjes, is het expression script block vereist en zijn de mode enumeration en het getaltoreturn integer argument optioneel, zodat u deze methode kunt aanroepen met 1, 2 of 3 argumenten. Als u een bepaald argument wilt gebruiken, moet u alle argumenten aan de linkerkant van dat argument opgeven (als u een waarde voor numberToReturn wilt opgeven, moet u ook waarden voor modus en expressie opgeven).

Where (scriptblock expression)

De meest basale aanroep van de Where methode neemt gewoon een scriptblock expression als argument. De script block expression zal eenmaal worden geëvalueerd voor elk object in de collectie die wordt verwerkt, en als het retourneert true, het object zal worden geretourneerd door de Where methode. Dit is het functionele equivalent van het aanroepen van de Where-Object cmdlet en het doorgeven van een script blok. Net als De Where-Object cmdlet, kunnen de variabelen $_ en $PSItem worden gebruikt om te verwijzen naar het huidige item dat wordt verwerkt terwijl het script blok.

Hier is een heel eenvoudig voorbeeld, dat laat zien hoe je een lijst met draaiende services kunt krijgen.

# Get all services$services = Get-Service# Now filter out any services that are not running$services.where{$_.Status -eq 'Running'}

Dit biedt geen nieuwe functionaliteit, maar het biedt veel snellere prestaties dan Where-Object en de syntaxis is vrij eenvoudig te volgen, dus je moet dit echt overwegen voor je scripts wanneer je client-side filtering uitvoert van collecties die je hebt opgeslagen in een variabele.

Where(scriptblock expression, WhereOperatorSelectionMode mode)

wanneer u begint te kijken naar de optionele parameters voor de Where methode, beginnen de dingen veel interessanter te worden. Windows PowerShell versie 4.0 bevat een nieuwe opsomming met een typename van het systeem.Management.Automatisering.WhereOperatorSelectionMode. Let op het achtervoegsel van die typename: “SelectionMode”. Het wordt gebruikt om krachtige selectie mogelijkheden in een waar syntaxis. Hier zijn de waarden opgenomen in deze opsomming, samen met hun definities:

Default Filter de collectie met de uitdrukking script blok, tot een maximum tellen als één of standaard op alle objecten in de collectie als er geen maximum aantal werd in numberToReturn.
First retourneer de eerste n objecten die het expressiescript block filter passeren, standaard naar slechts 1 object als een specifieke telling niet werd gevraagd in numberToReturn.
Last retourneer de laatste N objecten die het expressiescript block filter passeren, standaard naar slechts 1 object als een specifieke telling niet werd gevraagd in numberToReturn.
SkipUntil objecten in de verzameling overslaan totdat een object het expressiescript block filter passeert, en dan de eerste n objecten retourneren, standaard naar alle resterende objecten als er geen maximum aantal was opgegeven in numberToReturn.
Until retourneer de eerste n-objecten in een verzameling totdat een object het expressiescript block filter passeert, standaard naar alle objecten voorafgaand aan het eerste object dat werd doorgegeven als er geen maximumaantal werd opgegeven in numberToReturn.
splitsen Een verzameling in twee splitsen, alle objecten die het expressiescriptblokfilter doorgeven in de eerste verzameling plaatsen tot een maximumtelling als er een is opgegeven in numberToReturn, of alle objecten die overgaan als er geen maximumtelling is opgegeven, en alle andere objecten die niet in de eerste verzameling zijn geplaatst in de tweede verzameling plaatsen.

elk van deze biedt een unieke waarde wanneer u gegevensverzamelingen verwerkt, dus Ik zal hieronder meer details geven over elke selectiemodus.

Default

Het is niet verrassend dat de standaardwaarde van het modeargument ‘Default’is. De standaard selectiemodus biedt dezelfde functionaliteit die u krijgt als u helemaal geen selectiemodus biedt. Bijvoorbeeld, we hadden de laatste regel van ons vorige voorbeeld zo kunnen schrijven:

# Now filter out any services that are not running$services.where({$_.Status -eq 'Running'},'Default')

in dat voorbeeld is het extra argument echter niet nodig, omdat het precies hetzelfde doet als het zou doen als je het argument niet zou geven. U kunt ook het maximum aantal objecten opgeven dat u wilt retourneren tijdens het gebruik van de standaard selectiemodus met behulp van het argument numberToReturn, zoals dit:

# Get the first 10 services in our collection that are running$services.where({$_.Status -eq 'Running'},'Default',10)

Het is belangrijk op te merken dat exacte functionaliteit ook beschikbaar is bij het gebruik van de eerste selectie mode (waarover we het zo zullen hebben), dus het is echt niet praktisch om een van de optionele parameters te gebruiken wanneer u de standaard selectie mode gebruikt.

eerste

zoals u misschien al geraden hebt, kunt u met de eerste selectiemodus de eerste object(en) in de collectie selecteren die het script block expression filter passeren. Wanneer u eerst zonder waarde voor het getaltoreturnargument gebruikt, of wanneer u eerst met een waarde van 0 voor het getaltoreturnargument gebruikt, wordt alleen het eerste object dat het filter passeert geretourneerd. U kunt optioneel opgeven hoeveel objecten u wilt retourneren in het getaltoreturn argument, in welk geval dat veel objecten zullen worden geretourneerd (ervan uitgaande dat er zoveel objecten zijn die het filter passeren).

Hier zijn enkele voorbeelden die onze services-collectie gebruiken en de eerste selectiemodus in actie tonen:

# Get the first service in our collection that is running$services.where({$_.Status -eq 'Running'},'First')# Get the first service in our collection that is running$services.where({$_.Status -eq 'Running'},'First',1)# Get the first 10 services in our collection that are running$services.where({$_.Status -eq 'Running'},'First',10)

merk op dat het tweede commando in deze voorbeelden dezelfde resultaten geeft als het eerste commando, omdat het simpelweg expliciet De standaardwaarde van het getaltoreturn argument doorgeeft wanneer de eerste selectie mode wordt gebruikt.

Laatste

de laatste selectiemodus werkt vergelijkbaar met de eerste selectiemodus, waardoor u de laatste object(en) in de collectie kunt selecteren die het script block expression filter passeren. Wanneer u Last gebruikt zonder een waarde voor het getaltoreturnargument, of wanneer u Last gebruikt met een waarde van 0 voor het getaltoreturnargument, wordt alleen het laatste object dat het filter passeert geretourneerd. U kunt optioneel opgeven hoeveel objecten u wilt retourneren in het getaltoreturn argument, in welk geval dat veel objecten zullen worden geretourneerd (ervan uitgaande dat er zoveel objecten zijn die het filter passeren).

Hier zijn enkele voorbeelden die onze services collectie gebruiken en de laatste selectiemodus in actie tonen:

# Get the last service in our collection that is running$services.where({$_.Status -eq 'Running'},'Last')# Get the last service in our collection that is running$services.where({$_.Status -eq 'Running'},'Last',1)# Get the last 10 services in our collection that are running$services.where({$_.Status -eq 'Running'},'Last',10)

net als de eerste selectie mode voorbeelden geeft het tweede commando in deze voorbeelden dezelfde resultaten als het eerste commando omdat het gewoon expliciet De standaardwaarde van het getaltoreturn argument passeert wanneer de laatste selectie mode wordt gebruikt.

SkipUntil

met de selectiemodus SkipUntil kunt u alle objecten in een verzameling overslaan totdat u er een vindt die het script block expression filter passeert. Zodra u een object vindt dat het filter passeert, zal de SkipUntil-modus ofwel alle objecten die in de collectie achterblijven retourneren als er geen waarde of een waarde van 0 is opgegeven voor het argument numberToReturn, ofwel de eerste N resterende objecten in de collectie retourneren als er een waarde groter dan nul is opgegeven voor het argument numberToReturn. In beide gevallen zullen de resultaten het eerste object bevatten dat het filter passeerde.

Hier zijn enkele voorbeelden die een subset van onze services-collectie gebruiken om de SkipUntil-selectiemodus in actie te tonen:

# Get a collection of services whose name starts with "c"$services = Get-Service c*# Skip all services until we find one with a status of "Running"$services.where({$_.Status -eq 'Running'},'SkipUntil')# Skip all services until we find one with a status of "Running", then# return the first 2$services.where({$_.Status -eq 'Running'},'SkipUntil',2)

Until

De modus tot selectie biedt de tegenovergestelde functionaliteit van de modus SkipUntil tot selectie. Hiermee kunt u objecten in een verzameling retourneren totdat u er een vindt die het script block expression filter passeert. Zodra u een object vindt dat het filter passeert, stopt de Where-methode met het verwerken van objecten. Als u geen waarde opgeeft voor het argument numberToReturn, of als u een waarde van 0 opgeeft, retourneert de modus tot selectie alle objecten in de verzameling die leiden tot de eerste die het script block expression filter passeert. Als u een waarde opgeeft voor het argument numberToReturn dat groter is dan 0, zal de modus tot selectie maximaal dat aantal objecten retourneren, wat betekent dat het mogelijk niet eens een object vindt dat het script block expression filter passeert.

Hier zijn enkele voorbeelden die een andere subset van onze services collectie gebruiken om de modus tot selectie in actie te tonen:

# Get a collection of services whose name starts with "p"$services = Get-Service p*# Return all services until we find one with a status of "Stopped"$services.where({$_.Status -eq 'Stopped'},'Until')# Return the first 2 services unless we find one with a status of# "Stopped" first$services.where({$_.Status -eq 'Stopped'},'Until',2)

Split

Split selectie modus is uniek. In plaats van het retourneren van een deelverzameling van de collectie waarmee je begint in een nieuwe collectie, retourneert het een nieuwe collectie die intern twee afzonderlijke collecties bevat. Wat die geneste collecties bevatten hangt af van hoe je de Split selection mode gebruikt. Split staat u toe om een verzameling objecten in twee te splitsen. Als u standaard geen waarde opgeeft voor het argument numberToReturn of als u een waarde van 0 opgeeft voor het argument numberToReturn, plaatst Split alle objecten die het script block expression filter doorgeven in de eerste geneste collectie, en alle andere objecten (degene die het script block expression filter niet doorgeven) in de tweede geneste collectie. Als u een waarde groter dan 0 opgeeft voor het argument numberToReturn, zal split de grootte van de eerste verzameling beperken tot dat maximale bedrag, en alle resterende objecten in de collectie, zelfs die welke overeenkomen met het script block expression filter, zullen in de tweede verzameling worden geplaatst.

Hier zijn enkele voorbeelden die laten zien hoe Split selection mode gebruikt kan worden om een verzameling objecten op verschillende manieren op te splitsen:

# Get all services$services = Get-Service# Split the services into two groups: Running and not Running$running,$notRunning = $services.Where({$_.Status -eq 'Running'},'Split')# Show the Running services$running# Show the services that are not Running$notRunning# Split the services into the same two groups, but limit the Running group# to a maximum of 10 items$10running,$others = $services.Where({$_.Status -eq 'Running'},'Split',10)# Show the first 10 Running services$10running# Show all other services$others

zoals u in dit voorbeeld kunt zien, is Splitsen een krachtige selectiemodus, die een mix van filteren, groeperen en selectie biedt in een enkele opdracht aanroep.

Deze verzameling van selectie modes maakt de Where methode snel en elegant maar tegelijkertijd krachtiger dan de Where-Object, Group-Object en Select-Object gecombineerd in een enkele pijplijn. Wat is daar niet leuk aan?

tekortkomingen in de ForEach en waar script methoden in TypePx

zoals ik eerder in dit artikel vermeld, heb ik type extensies geschreven voor PowerShell 3.0 en later en verpakt ze in een module genaamd TypePx. TypePx is een script module die volledig is geschreven in PowerShell, en het draait op PowerShell 3.0 of hoger. Als je PowerShell 3.0 gebruikt (en alleen als je PowerShell 3.0 gebruikt), definieert TypePx ForEach en waar scriptmethoden die het gedrag van de ForEach nabootsen en waar methoden in PowerShell 4.0 en later. Terwijl het extended type systeem in PowerShell het mogelijk maakt om dit gedrag na te bootsen, zijn er een paar tekortkomingen te wijten aan de implementatie in PowerShell die invloed had op hoe ver ik in staat was om te gaan met deze type extensies. Deze sectie zal een aantal van de verschillen en beperkingen beschrijven die bestaan in de ForEach en waar script methoden in TypePx waar je misschien bewust van wilt zijn als je PowerShell 3.0 gebruikt.

Scriptblokken aangeroepen vanuit een scriptmethode worden uitgevoerd in een dochterscope

In tegenstelling tot de ForEach en waar methoden geïmplementeerd zijn als onderdeel van PowerShell 4.0 of hoger die het expressie script blok in de huidige scope aanroepen waar de methode wordt aangeroepen, de ForEach en waar script methoden geà mplementeerd in PowerShell 3.0 het expressie script blok aanroepen in een dochter scope. Dit is een beperking in PowerShell die er al vanaf het allereerste begin is (een beperking, mag ik toevoegen, die volgens mij veruit de grootste tekortkoming is van PowerShell als taal).

vanwege deze beperking worden alle variabelen die u binnen een expressiescriptblok toewijst, alleen gewijzigd in de onderliggende scope. Dit heeft implicaties als je expression script block bedoeld is om een variabele te updaten in de scope waarin je ForEach of Where aanroept. Het is onwaarschijnlijk dat dit een probleem zou veroorzaken tijdens het gebruik van Where omdat het niet erg gebruikelijk is om variabelen te wijzigen in een Where expressie script blok, maar in ForEach script blokken kan dit een probleem vormen, dus je moet dit in gedachten houden als je deze extensies gebruikt.

Ik merk op dat ik deze beperking helemaal wil verwijderen, en ik denk dat ik dat kan doen, maar op het moment dat ik dit artikel schreef heb ik hier nog geen oplossing voor geïmplementeerd.

de meeste, maar niet alle collecties zullen ForEach hebben en waar methoden

In PowerShell 4.0 en later, de ForEach en waar methoden op magische wijze beschikbaar worden gemaakt voor alle types die IEnumerable implementeren behalve voor String, XmlNode en types die IDictionary implementeren. In PowerShell staat het extended type systeem geen uitbreidingen toe voor interfaces, alleen voor types. Dit is een uitdaging als je een brede extensie wilt creëren zoals ForEach en Where. In de huidige implementatie van deze uitbreidingen in TypePx, de TypePx module vindt alle soorten in alle vergaderingen geladen in de huidige app domein, en voor alle niet-generieke typen die bepalen IEnumerable maar niet IDictionary (exclusief String en XmlNode), plus voor alle algemene soorten die bepalen IEnumerable maar niet IDictionary voor algemene collecties van PSObject, Object, String, Int32, of Int64, de ForEach en Waar script methoden zullen worden gemaakt.

Dit heeft betrekking op een groot aantal typen die in mijn eigen testen voldoende zijn geweest, maar u kunt typen tegenkomen waar u deze methoden wilt gebruiken en ze zijn niet beschikbaar. Als dat het geval is, laat het me weten via GitHub en Ik zal zien wat ik kan doen. Dit is ook een beperking die ik zou willen verwijderen, maar ik heb meer tijd nodig om te onderzoeken hoe de gelijkwaardige functionaliteit te implementeren in een gecompileerde assembly waar ik in staat kan zijn om het meer te definiëren zoals het is gedefinieerd in PowerShell 4.0 en later.

PowerShell-scripts zijn niet zo snel als gecompileerde code

dit spreekt waarschijnlijk vanzelf, maar als je iets in PowerShell schrijft, wat een geà nterpreteerde taal is, zal het niet zo snel werken als wanneer je de equivalente logica in een taal als C#zou schrijven. Dit is absoluut het geval voor de foreach en Where script methoden, die intern ForEach-Object, Where-Object, en pipelining gebruiken om het gedrag van de inheemse ForEach en Where methoden na te bootsen. In dit geval, het voordeel van het hebben van deze commando ‘ s komt van de elegante syntaxis en functionaliteit die ze bieden, plus de mogelijkheid om deze te gebruiken in scripts voor PowerShell 3.0 en 4.0. De performance voordelen in ForEach en Where zijn alleen in de PowerShell 4.0 native implementatie.

PowerShell 3.0 vereist haakjes rond alle methodeparameters

Ik noemde in de voorbeelden hierboven dat ik in staat was om een methode aan te roepen met een enkele letterlijke scriptblokparameter zonder dat letterlijke scriptblok tussen extra haakjes te wikkelen. Die mogelijkheid bestaat alleen in PowerShell 4.0 of later als gevolg van verbeteringen die zijn aangebracht aan de parser in die release. In PowerShell 3.0 ondersteunt de parser dit niet, dus haakjes zijn altijd nodig om de ForEach en waar script methoden om te werken met een enkele letterlijke script blok parameter in die versie.

conclusie

toen ik begon te proberen het gedrag van de ForEach na te bootsen en waar magische methoden in PowerShell 3.0, realiseerde ik me niet helemaal hoeveel functionaliteit ze boden. Graven in de technische details achter deze methoden, zodat ik de extensies die ik wilde in TypePx kon maken hielp ontdekken alle verborgen functies in deze zeer krachtige methoden, en ik ben erg blij om die met u te delen in dit artikel. Ik hoop dat deze informatie U helpt gebruik te maken van deze prachtige nieuwe set van functies in uw PowerShell werk, zelfs als je nog steeds met behulp van PowerShell 3.0. Gelukkig scripting!