Articles

ForEach och Where magic methods

ForEach och var finns två ofta använda begrepp som har funnits i PowerShell sedan version 1 kom ut 2006. ForEach har varit tillgänglig som både ett uttalande och en cmdlet (ForEach-Object), så att du kan iterera genom en samling objekt och vidta några åtgärder en gång för varje objekt i den samlingen. Where har varit tillgängligt som en cmdlet (Where-Object), så att du kan filtrera bort objekt i en samling som inte klarar något villkor, ett villkor som kan utvärderas med antingen egenskaperna på objekt i samlingen eller själva objekten som tillhör samlingen. ForEach-förmågan att vidta åtgärder på objekt i en samling och där förmågan att filtrera en samling är funktioner som är mycket användbara och ingår i en eller annan form i logiken bakom många PowerShell-skript, kommandon och moduler, oavsett vilken version av PowerShell som används. Faktum är att de används så kraftigt att de har varit ett fokusområde för förbättring av prestanda, funktionalitet och syntax i PowerShell-versionerna 3.0 och 4.0.

med lanseringen av Windows PowerShell 4.0 introducerades två nya” magiska ” metoder för samlingstyper som ger en ny syntax för åtkomst till ForEach och where-funktioner i Windows PowerShell. Dessa metoder heter lämpligt förvar och var. Jag kallar dessa metoder ”magiska” eftersom de är ganska magiska i hur de arbetar i PowerShell. De dyker inte upp I Get-Member output, även om du ansöker-Force och request-MemberType All. Om du rullar upp ärmarna och gräver in med reflektion kan du hitta dem; det kräver dock en bred sökning eftersom de är privata förlängningsmetoder som implementeras på en privat klass. Men även om de inte är upptäckbara utan att kika under omslaget, är de där när du behöver dem, de är snabbare än sina äldre motsvarigheter, och de inkluderar funktionalitet som inte var tillgänglig i sina äldre motsvarigheter, därav den ”magiska” känslan de lämnar dig med när du använder dem i PowerShell. Tyvärr förblir dessa metoder papperslösa även idag, nästan ett år sedan de släpptes offentligt, så många människor inser inte kraften som finns i dessa metoder. Den här artikeln kommer att försöka korrigera det genom att förklara var de kan användas och hur de fungerar så att du kan utnyttja denna magi när du använder PowerShell.

en anteckning om PowerShell 3.0

innan jag förklarar hur ForEach och var metoderna fungerar, måste jag nämna något med avseende på dessa två metoder och PowerShell 3.0. Även om det är sant att ForEach och where-metoderna endast gjordes tillgängliga i PowerShell 4.0 och senare versioner, PowerShell 3.0 används fortfarande mycket i många miljöer, och om du inte använder PowerShell i en miljö som har standardiserats på PowerShell 4.0 och senare kan du hitta dig själv som önskar att du kan dra nytta av syntaxen som tillhandahålls av de nya metoderna när du använder PowerShell 3.0. Jag kände att detta var en begränsning värt att ta itu med, så som en del av TypePx-modulen som jag nyligen publicerade på GitHub och i PowerShell Resource Gallery (aka PowerShellGet public repository, för närvarande i Begränsad förhandsgranskning), inkluderade jag ForEach och där skriptmetoder som funktionellt motsvarar de metoder som introducerades i PowerShell 4.0 så att du kan utnyttja den nya syntaxen och funktionaliteten även om du använder PowerShell 3.0. Det finns några brister i denna implementering, som jag kommer att lyfta fram senare i den här artikeln.

ForEach-metoden

ForEach är en metod som gör att du snabbt kan iterera genom en samling objekt och vidta några åtgärder på varje objekt i den samlingen. Denna metod ger snabbare prestanda än sina äldre motsvarigheter (foreach-uttalandet och ForEach-Object cmdlet), och det förenklar också några av de vanligaste åtgärderna som du kanske vill ta på objekten i samlingen. Alla objekt som matas ut med denna metod returneras i en generisk samling av typsystem.Samling.Objektmodell.Samling1.

det finns sex sätt som stöds som du kan åberopa denna metod, och var och en av dessa kommer att förklaras mer detaljerat nedan. De argument som stöds som kan användas när man åberopar ForEach-metoden är följande:

  • ForEach(scriptblock expression)
  • ForEach(typ convertToType)
  • ForEach(string propertyName)
  • ForEach(string propertyName, object newValue)
  • ForEach(string methodName)
  • ForEach(string methodName, object arguments)
  • ForEach(string methodName, object arguments)
  • ForEach (scriptblock expression, object arguments)

Observera att dessa stöds argumentparningar, inte olika överbelastningar tillgängliga för foreach-metoden. Att använda andra argumentparningar än dessa kan leda till fel som inte tydligt identifierar vad det faktiska problemet är.

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

Om du skickar ett scriptblockuttryck i ForEach-metoden kan du utföra samma typ av uppgifter som du skulle göra i ett scriptblock som du skulle använda med foreach-uttalandet eller ForEach-Object cmdlet. Liksom ForEach-Object cmdlet refererar både $ _ och $ PSItem-variablerna till det aktuella objektet som behandlas. Alla argument som du tillhandahåller utöver det ursprungliga skriptblockargumentet kommer att användas som argument för skriptblocket. Det här är precis som hur parametern-ArgumentList fungerar på ForEach-Object cmdlet. Här är ett exempel som visar hur du kan använda detta för att utföra ett skriptblock på varje objekt i en samling:

# 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')

Du kanske har märkt något konstigt om denna syntax, eftersom jag inte slog in skriptblocket i parentes. Du kan linda in den i runda parenteser, men det är valfritt i PowerShell 4.0 eller senare eftersom PowerShell-parsern förbättrades så att parenteserna kan utelämnas när du åberopar en metod som accepterar ett enda skriptblockargument. Liksom foreach-uttalandet och ForEach-Object cmdlet åberopas skriptblocket som du tillhandahåller i det aktuella omfånget. Det betyder att alla variabla uppdrag du gör inuti det skriptblocket kommer att bestå efter att ForEach-metoden har slutförts.

ForEach(typ convertToType)

unikt för ForEach-metoden kan du skicka en typ till ForEach-metoden om du vill konvertera varje objekt i en samling till en annan typ. Tänk dig till exempel att du har en samling objekt och du vill konvertera dessa objekt till deras strängekvivalent. Här är vad det skulle se ut med ForEach-metoden:

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

Du kunde ha utfört samma uppgift genom att typecasting samlingen i en rad typsträngar (t.ex.] $processer), och typecasting matrisen är faktiskt betydligt snabbare, men det finns en mycket god chans att du inte ens skulle märka skillnaden i körtid om du inte arbetade med en mycket, mycket stor samling. Trots tidsskillnaden tenderar jag att föredra ForEach method syntax i vissa situationer om det tillåter mig att behålla elegans i implementeringen genom att undvika extra runda parenteser i de skript jag skriver.

ForEach (string propertyName)

i PowerShell 3.0 och senare lades en andra parameteruppsättning till ForEach-Object så att du lättare kan hämta värdet på en specifik egenskap genom att helt enkelt skicka in ett egenskapsnamn som det enda parametervärdet för ForEach-Object. Denna bekvämlighet har också erbjudits i ForEach-metoden. Här är ett exempel som visar hur du kan iterera genom en samling och returnera en egenskap i den samlingen:

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

naturligtvis sedan version 3.0 av PowerShell kan du helt enkelt åberopa $services.Name för att få namnen på alla tjänster, och det kommer att slutföras snabbare än ForEach method-alternativet (även om du bara märker prestandaskillnaden i mycket stora samlingar i storleksordningen hundratusentals objekt); men det fungerar bara för egenskaper som inte finns på själva samlingen, och det är en syntax som vissa scripters inte är bekväma med på grund av den implicita karaktären av vad kommandot gör. Den nya ForEach method syntax ger dig ett mer explicit alternativ som har den extra fördelen att vara lite mer självdokumenterande också.

ForEach(string propertyName, object newValue)

Du kan inte bara hämta en egenskap på en samling objekt, du kan också ställa in en egenskap på en samling objekt. Det här är funktionalitet som inte är tillgänglig i de andra foreach-erna, såvida du inte uttryckligen skapar skriptblocket för att göra det. För att ställa in egenskapen anger du helt enkelt egenskapsnamnet och det värde du vill använda när du ställer in den egenskapen, så här:

# 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')

precis som uppdrag du skulle göra med equals-operatören försöker PowerShell konvertera vad du än anger som det nya värdet till lämplig typ för egenskapen som tilldelas.

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

för att åberopa en metod anger du helt enkelt metodnamnet som det första argumentet och sedan argumenten för den metoden som den andra, tredje, fjärde etc. argument. Om metoden inte tar några argument kan du helt enkelt skicka in metodnamnet och det kommer att åberopas utan några argument. Här är ett exempel som visar hur du kan döda en massa processer som kör ett specifikt program:

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

Här är ett annat exempel, den här gången med en metod med argument medan du visar hur du kan verifiera att kommandon följer bästa praxis genom att använda lämpliga namn och alias för vanliga parametrar:

# 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

som du kan se från dessa resultat finns det definitivt några inkonsekvenser i implementeringen av Datornamnsparametrar som bör korrigeras.

som täcker alla funktioner som för närvarande finns i ForEach-metoden. Som du kan se finns det inte mycket ny funktionalitet som erbjuds i den här metoden, men syntaxförbättringarna när du utför en enkel uppgift på en samling objekt är trevliga, och ForEach-metodens prestandaförbättringar jämfört med motsvarande foreach-uttalande för ForEach-Object pipeline är definitivt en välkommen förbättring också. Med den förklaringen ur vägen, låt oss gå vidare till Where-metoden.

Where-metoden

Where är en metod som låter dig filtrera en samling objekt. Det här är väldigt mycket som Where-Object cmdlet, men Where-metoden är också som Select-Object och Group-Object, innehåller flera ytterligare funktioner som Where-Object cmdlet inte naturligt stöder av sig själv. Denna metod ger snabbare prestanda än Where-Object i ett enkelt, elegant kommando. Liksom ForEach-metoden returneras alla objekt som matas ut med denna metod i en generisk samling av typsystem.Samling.Objektmodell.Samling1.

det finns bara en version av denna metod, som kan beskrivas enligt följande:

Where(scriptblock expression])

som indikeras av hakparenteserna krävs uttryckskriptblocket och lägesräkningen och numberToReturn-heltalsargumentet är valfria, så du kan åberopa denna metod med 1, 2 eller 3 argument. Om du vill använda ett visst argument måste du ange alla argument till vänster om det argumentet (dvs. om du vill ange ett värde för numberToReturn måste du också ange värden för läge och uttryck).

Where (scriptblock expression)

den mest grundläggande åkallan av Where-metoden tar helt enkelt ett skriptblockuttryck som ett argument. Skriptblockuttrycket utvärderas en gång för varje objekt i samlingen som behandlas, och om det returnerar true returneras objektet med Where-metoden. Detta är den funktionella motsvarigheten till att ringa Where-Object cmdlet och skicka det ett skriptblock. Liksom Where-Object cmdlet kan $ _ och $ PSItem-variablerna användas för att hänvisa till det aktuella objektet som behandlas medan du är inne i skriptblocket.

Här är ett mycket enkelt exempel som visar hur du kan få en lista över löpande tjänster.

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

detta erbjuder inte någon ny funktionalitet, men det ger mycket snabbare prestanda än Where-Object och syntaxen är ganska lätt att följa, så du borde verkligen överväga detta för dina skript när du utför klientfiltrering av samlingar som du har lagrat i en variabel.

Where (scriptblock expression, Wheroperatorselectionmode mode)

När du börjar titta på de valfria parametrarna för Where-metoden börjar sakerna bli mycket mer intressanta. Windows PowerShell version 4.0 inkluderade en ny uppräkning med ett typnamn på systemet.Förvaltning.Automation.WhereOperatorSelectionMode. Notera suffixet för den typnamnet:”SelectionMode”. Det används för att ge kraftfulla urvalsfunktioner i en där syntax. Här är de värden som ingår i denna uppräkning, tillsammans med deras definitioner:

Default filtrera samlingen med hjälp av skriptblocket expression, till ett maximalt antal om en tillhandahölls eller standard för alla objekt i samlingen om inget maximalt antal tillhandahölls i numbertoreturn.
första returnera de första n-objekten som passerar expression script block-filtret, som standard till endast 1 objekt om ett specifikt antal inte begärdes i numberToReturn.
Last returnera de sista n-objekten som passerar expression script block-filtret, som standard till endast 1 objekt om ett specifikt antal inte begärdes i numberToReturn.
SkipUntil hoppa över objekt i samlingen tills ett objekt passerar expression scriptblockfiltret och returnera sedan de första n-objekten, som standard till alla återstående objekt om inget maximalt antal tillhandahölls i numberToReturn.
tills returnera de första n-objekten i en samling tills ett objekt passerar expression script block-filtret, som standard till alla objekt som leder fram till det första objektet som passerade om inget maximalt antal tillhandahölls i numberToReturn.
Split dela upp en samling i två, placera alla objekt som passerar expression script block filter i den första samlingen upp till ett maximalt antal om ett tillhandahölls i numberToReturn, eller alla objekt som passerar om inget maximalt antal tillhandahölls, och placera alla andra objekt som inte sätts i den första samlingen i den andra samlingen samling.

var och en av dessa erbjuder ett unikt värde när du behandlar samlingar av data, så jag ger mer information om varje valläge nedan.

Default

inte överraskande är standardvärdet för lägesargumentet ’Default’. Standardvalsläget erbjuder samma funktionalitet som du får när du inte tillhandahåller ett urvalsläge alls. Till exempel kunde vi ha skrivit den sista raden i vårt tidigare exempel så här:

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

i det exemplet är det extra argumentet inte nödvändigt, eftersom det gör exakt samma sak som det skulle göra om du inte gav argumentet. Du kan också ange det maximala antalet objekt som du vill returnera när du använder standardvalsläge med argumentet numberToReturn, så här:

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

det är viktigt att notera att exakt funktionalitet också är tillgänglig när du använder det första valläget (som vi pratar om på ett ögonblick), så det är verkligen inte praktiskt att använda någon av de valfria parametrarna alls när du använder standardvalsläget.

först

som du kanske har gissat kan du välja det första objektet i samlingen som passerar skriptblockuttrycksfiltret. När du använder först utan ett värde för numberToReturn-argumentet, eller när du använder först med ett värde på 0 för numbertoreturn-argumentet, returneras endast det första objektet som passerar filtret. Du kan valfritt ange hur många objekt som ska returneras i numberToReturn-argumentet, i vilket fall många objekt kommer att returneras (förutsatt att det finns så många objekt som passerar filtret).

Här är några exempel som använder vår tjänstesamling som visar det första urvalsläget i aktion:

# 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)

Observera att det andra kommandot i dessa exempel returnerar samma resultat som det första kommandot eftersom det helt enkelt uttryckligen passerar i standardvärdet för numberToReturn-argumentet när det första markeringsläget används.

Last

det sista markeringsläget fungerar ungefär som det första markeringsläget, så att du kan välja de sista objekten i samlingen som passerar skriptblockuttrycksfiltret. När du använder Last without a value för numbertoreturn-argumentet, eller när du använder Last with a value of 0 för numbertoreturn-argumentet, returneras endast det sista objektet som passerar filtret. Du kan valfritt ange hur många objekt som ska returneras i numberToReturn-argumentet, i vilket fall många objekt kommer att returneras (förutsatt att det finns så många objekt som passerar filtret).

Här är några exempel som använder vår tjänstesamling som visar det senaste urvalsläget i aktion:

# 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)

liksom de första exemplen på urvalsläge returnerar det andra kommandot i dessa exempel samma resultat som det första kommandot eftersom det helt enkelt uttryckligen passerar standardvärdet för numberToReturn-argumentet när det sista markeringsläget används.

SkipUntil

med SkipUntil selection-läget kan du hoppa över alla objekt i en samling tills du hittar ett som passerar skriptblockuttrycksfiltret. När du har hittat ett objekt som passerar filtret returnerar SkipUntil mode antingen alla objekt som finns kvar i samlingen om inget värde eller ett värde på 0 tillhandahölls till numbertoreturn-argumentet, eller det returnerar de första n återstående objekten i samlingen om ett värde större än noll tillhandahölls till numbertoreturn-argumentet. I båda fallen kommer resultaten att innehålla det första objektet som passerade filtret.

Här är några exempel som använder en delmängd av vår tjänstesamling för att visa läget SkipUntil selection i aktion:

# 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)

tills

läget tills val ger motsatt funktionalitet i läget SkipUntil selection. Det låter dig returnera objekt i en samling tills du hittar en som passerar skriptblockuttrycksfiltret. När du har hittat ett objekt som passerar filtret slutar Where-metoden att bearbeta objekt. Om du inte anger ett värde för numberToReturn-argumentet, eller om du anger ett värde på 0, returnerar läget tills val alla objekt i samlingen fram till det första som passerar skriptblockuttrycksfiltret. Om du anger ett värde för numbertoreturn-argumentet som är större än 0, returnerar läget tills selection högst det antalet objekt, vilket betyder att det kanske inte ens hittar ett objekt som passerar skriptblockuttrycksfiltret.

Här är några exempel som använder en annan delmängd av vår tjänstesamling för att visa läget tills val i aktion:

# 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 selection mode är unikt. Istället för att returnera en delmängd av samlingen du börjar med i en ny samling returnerar den en ny samling som internt innehåller två separata samlingar. Vad de kapslade samlingarna innehåller beror på hur du använder Split selection mode. Split låter dig dela upp en samling objekt i två. Som standard, om du inte anger ett värde för numbertoreturn-argumentet eller om du anger ett värde på 0 för numbertoreturn-argumentet, kommer Split att placera alla objekt som passerar skriptblockuttrycksfiltret i den första kapslade samlingen och alla andra objekt (de som inte passerar skriptblockuttrycksfiltret) i den andra kapslade samlingen. Om du anger ett värde som är större än 0 för numberToReturn-argumentet begränsar split storleken på den första samlingen till det maximala beloppet, och alla återstående objekt i samlingen, även de som matchar skriptblockuttrycksfiltret, placeras i den andra samlingen.

Här är några exempel som visar hur Split selection mode kan användas för att dela upp en samling objekt på olika sätt:

# 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

som du kan se från det här exemplet är Split ett ganska kraftfullt urvalsläge, vilket ger en blandning av filtrering, gruppering och val i ett enda kommandosamtal.

denna samling av urvalslägen gör Where-metoden snabb och elegant men samtidigt kraftfullare än Where-Object, Group-Object och Select-Object kombinerat i en enda pipeline. Vad är inte att älska om det?

brister i ForEach och där skriptmetoder i TypePx

som jag nämnde tidigare i den här artikeln har jag skrivit typtillägg för PowerShell 3.0 och senare och förpackade dem i en modul som heter TypePx. TypePx är en skriptmodul som skrevs helt i PowerShell, och den körs på PowerShell 3.0 eller senare. Om du använder PowerShell 3.0 (och bara om du använder PowerShell 3.0) definierar TypePx ForEach och Where script-metoder som efterliknar Foreachs beteende och where-metoder i PowerShell 4.0 och senare. Medan det utökade typsystemet i PowerShell gör det möjligt att efterlikna detta beteende, finns det några brister på grund av att implementeringen är i PowerShell som påverkade hur långt jag kunde gå med dessa typförlängningar. Det här avsnittet beskriver några av de skillnader och begränsningar som finns i ForEach och där skriptmetoder i TypePx som du kanske vill vara medveten om om du använder PowerShell 3.0.

Skriptblock som anropas från en skriptmetod körs i ett barnomfång

Till skillnad från ForEach och där metoder implementeras som en del av PowerShell 4.0 eller senare som åberopar uttryckskriptblocket i det aktuella omfånget där metoden kallas, ForEach och där skriptmetoder implementerade i PowerShell 3.0 åberopar uttryckskriptblocket i ett barnomfång. Detta är en begränsning i PowerShell som har varit där sedan början (en begränsning, kan jag tillägga, som jag tycker är den överlägset största bristen på PowerShell som språk).

på grund av denna begränsning ändras alla variabler som du tilldelar inuti ett uttryckskriptblock endast i barnomfånget. Detta har konsekvenser om ditt uttryckskriptblock är avsett att uppdatera en variabel i det omfattning som du åberopar ForEach eller Where. Det är osannolikt att detta skulle orsaka ett problem när du använder var eftersom det inte är så vanligt att ändra variabler i ett where expression script block, men i ForEach script blocks kan detta utgöra ett problem så du måste ha detta i åtanke om du använder dessa tillägg.

jag bör notera att jag skulle vilja ta bort denna begränsning helt och hållet, och jag tror att jag kommer att kunna göra det, men när jag skrev den här artikeln har jag ännu inte implementerat en fix för detta.

de flesta, men inte alla samlingar kommer att ha ForEach och där metoder

i PowerShell 4.0 och senare, ForEach och där metoder magiskt görs tillgängliga för alla typer som implementerar IEnumerable förutom sträng, XmlNode och typer som implementerar IDictionary. I PowerShell tillåter det utökade typsystemet inte att tillägg skapas för gränssnitt, bara för typer. Det här är en utmaning om du vill skapa en bred förlängning som ForEach and Where. I den nuvarande implementeringen av dessa tillägg i TypePx hittar typepx-modulen alla typer i alla sammansättningar som laddas i den aktuella appdomänen och för alla icke-generiska typer som definierar IEnumerable men inte IDictionary (exklusive String och XmlNode), plus för alla generiska typer som definierar IEnumerable men inte IDictionary för generiska samlingar av PSObject, Object, String, Int32 eller Int64, ForEach och Where scriptmetoder kommer att skapas.

detta täcker ett stort antal typer som i min egen testning har varit tillräckliga, men du kan stöta på typer där du vill använda dessa metoder och de är inte tillgängliga. Om så är fallet, låt mig veta genom GitHub och jag ska se vad jag kan göra. Detta är också en begränsning som jag skulle vilja ta bort, men jag behöver mer tid att undersöka hur man implementerar motsvarande funktionalitet i en sammanställd enhet där jag kanske kan definiera den mer som den definieras i PowerShell 4.0 och senare.

PowerShell-skript är inte lika snabba som kompilerad kod

detta är förmodligen självklart, men när du skriver något i PowerShell, vilket är ett tolkat språk, körs det inte så snabbt som om du skrev motsvarande logik på ett språk som C#. Detta är absolut fallet för ForEach och Where script-metoder, som internt använder ForEach-Object, Where-Object och pipelining för att efterlikna beteendet hos de infödda ForEach och where-metoderna. I det här fallet kommer fördelen med att ha dessa kommandon från den eleganta syntaxen och funktionaliteten de tillhandahåller, plus att kunna använda dessa i skript för PowerShell 3.0 och 4.0. Prestandafördelarna i ForEach och var finns bara i PowerShell 4.0 native implementation.

PowerShell 3.0 kräver parenteser runt alla metodparametrar

jag nämnde i exemplen ovan att jag kunde åberopa en metod med en enda bokstavlig skriptblockparameter utan att förpacka det bokstavliga skriptblocket i ytterligare parenteser. Den förmågan finns bara i PowerShell 4.0 eller senare på grund av förbättringar som gjordes till tolkaren i den utgåvan. I PowerShell 3.0 stöder parsern inte detta, så parentes krävs alltid för att ForEach och Where-skriptmetoder ska fungera med en enda bokstavlig skriptblockparameter i den versionen.

slutsats

När jag började försöka efterlikna Foreachs beteende och var magiska metoder i PowerShell 3.0 insåg jag inte riktigt hur mycket funktionalitet de tillhandahöll. Att gräva i de tekniska detaljerna bakom dessa metoder så att jag kunde skapa de tillägg jag ville ha i TypePx hjälpte till att avslöja alla dolda funktioner i dessa mycket kraftfulla metoder, och jag är väldigt glad att dela dem med dig i den här artikeln. Jag hoppas att den här informationen hjälper dig att utnyttja denna underbara nya uppsättning funktioner i ditt PowerShell-arbete, även om du fortfarande använder PowerShell 3.0. Glad skript!