Dela via


ForEach-Object

Utför en åtgärd mot varje objekt i en samling indataobjekt.

Syntax

ForEach-Object
            [-InputObject <PSObject>]
            [-Begin <ScriptBlock>]
            [-Process] <ScriptBlock[]>
            [-End <ScriptBlock>]
            [-RemainingScripts <ScriptBlock[]>]
            [-WhatIf]
            [-Confirm]
            [<CommonParameters>]
ForEach-Object
            [-InputObject <PSObject>]
            [-MemberName] <String>
            [-ArgumentList <Object[]>]
            [-WhatIf]
            [-Confirm]
            [<CommonParameters>]
ForEach-Object
            -Parallel <scriptblock>
            [-InputObject <psobject>]
            [-ThrottleLimit <int>]
            [-TimeoutSeconds <int>]
            [-AsJob]
            [-UseNewRunspace]
            [-WhatIf]
            [-Confirm]
            [<CommonParameters>]

Description

Cmdleten ForEach-Object utför en åtgärd på varje objekt i en samling indataobjekt. Indataobjekten kan skickas till cmdleten eller anges med hjälp av parametern InputObject.

Från och med Windows PowerShell 3.0 finns det två olika sätt att konstruera ett ForEach-Object kommando.

  • Skriptblock. Du kan använda ett skriptblock för att ange åtgärden. Använd variabeln $_ i skriptblocket för att representera det aktuella objektet. Skriptblocket är värdet för parametern Process. Skriptblocket kan innehålla valfritt PowerShell-skript.

    Följande kommando hämtar till exempel värdet för egenskapen ProcessName för varje process på datorn.

    Get-Process | ForEach-Object {$_.ProcessName}

    ForEach-Object stöder blocken begin, processoch end enligt beskrivningen i about_Functions.

    Not

    Skriptblocken körs i anroparens omfång. Därför har blocken åtkomst till variabler i det omfånget och kan skapa nya variabler som finns kvar i omfånget när cmdleten har slutförts.

  • Åtgärdsuttryck. Du kan också skriva en åtgärdsinstruktur som är mycket mer likt naturligt språk. Du kan använda åtgärdssatsen för att ange ett egenskapsvärde eller anropa en metod. Åtgärdsinstruktioner introducerades i Windows PowerShell 3.0.

    Följande kommando hämtar till exempel även värdet för egenskapen ProcessName för varje process på datorn.

    Get-Process | ForEach-Object ProcessName

  • Skriptblock som körs parallellt. Från och med PowerShell 7.0 är en tredje parameteruppsättning tillgänglig som kör varje skriptblock parallellt. Parametern ThrottleLimit begränsar antalet parallella skript som körs åt gången. Precis som tidigare använder du variabeln $_ för att representera det aktuella indataobjektet i skriptblocket. Använd Using: omfångsmodifierare för att skicka variabelreferenser till skriptet som körs.

    I PowerShell 7 skapas en ny runspace för varje loop-iteration för att säkerställa maximal isolering. Detta kan vara en stor prestanda- och resursträff om det arbete du utför är litet jämfört med att skapa nya runspaces eller om det finns många iterationer som utför betydande arbete. Från och med PowerShell 7.1 återanvänds runspaces från en runspace-pool som standard. Parametern ThrottleLimit anger storleken på runspace-poolen. Standardstorleken för runspace-poolen är 5. Du kan fortfarande skapa en ny runspace för varje iteration med hjälp av växeln UseNewRunspace.

    Som standard använder parallella scriptblocks den aktuella arbetskatalogen för anroparen som startade de parallella uppgifterna.

    Mer information finns i avsnittet NOTES i den här artikeln.

Exempel

Exempel 1: Dela upp heltal i en matris

Det här exemplet tar en matris med tre heltal och delar var och en av dem med 1024.

30000, 56798, 12432 | ForEach-Object -Process {$_/1024}

29.296875
55.466796875
12.140625

Exempel 2: Hämta längden på alla filer i en katalog

I det här exemplet bearbetas filerna och katalogerna i PowerShell-installationskatalogen $PSHOME.

Get-ChildItem $PSHOME |
  ForEach-Object -Process {if (!$_.PSIsContainer) {$_.Name; $_.Length / 1024; " " }}

Om objektet inte är en katalog hämtar skriptblocket namnet på filen, delar upp värdet för egenskapen Length med 1024 och lägger till ett blanksteg (" ") för att separera det från nästa post. Cmdleten använder egenskapen PSIsContainer för att avgöra om ett objekt är en katalog.

Exempel 3: Arbeta med de senaste systemhändelserna

I det här exemplet skrivs de 1 000 senaste händelserna från systemhändelseloggen till en textfil. Den aktuella tiden visas före och efter bearbetning av händelserna.

Get-EventLog -LogName System -Newest 1000 |
    ForEach-Object -Begin {Get-Date} -Process {
        Out-File -FilePath Events.txt -Append -InputObject $_.Message
    } -End {Get-Date}

Get-EventLog hämtar de 1 000 senaste händelserna från systemhändelseloggen och skickar dem till ForEach-Object-cmdleten. Parametern Begin visar aktuellt datum och tid. Parametern Process använder sedan cmdleten Out-File för att skapa en textfil med namnet events.txt och lagrar meddelandeegenskapen för var och en av händelserna i filen. Slutligen används parametern End för att visa datum och tid när all bearbetning har slutförts.

Exempel 4: Ändra värdet för en registernyckel

I det här exemplet ändras värdet för RemotePath registerpost i alla undernycklar under HKCU:\Network nyckel till versaler.

Get-ItemProperty -Path HKCU:\Network\* |
  ForEach-Object {
    Set-ItemProperty -Path $_.PSPath -Name RemotePath -Value $_.RemotePath.ToUpper()
  }

Du kan använda det här formatet för att ändra formuläret eller innehållet i ett registerpostvärde.

Varje undernyckel i nyckeln Network representerar en mappad nätverksenhet som återansluter vid inloggning. Posten RemotePath innehåller UNC-sökvägen för den anslutna enheten. Om du till exempel mappar den E: enheten till \\Server\Shareskapas en E-undernyckel i HKCU:\Network med registervärdet RemotePath inställt på \\Server\Share.

Kommandot använder cmdleten Get-ItemProperty för att hämta alla undernycklar för Network-nyckeln och cmdleten Set-ItemProperty för att ändra värdet för registerposten RemotePath i varje nyckel. I kommandot Set-ItemProperty är sökvägen värdet för egenskapen PSPath för registernyckeln. Det här är en egenskap för Microsoft .NET Framework-objektet som representerar registernyckeln, inte en registerpost. Kommandot använder metoden ToUpper() för värdet RemotePath, som är en sträng REG_SZ.

Eftersom Set-ItemProperty ändrar egenskapen för varje nyckel krävs ForEach-Object cmdlet för att få åtkomst till egenskapen.

Exempel 5: Använd den $null automatiska variabeln

Det här exemplet visar effekten av att skicka $null automatisk variabel till cmdleten ForEach-Object.

1, 2, $null, 4 | ForEach-Object {"Hello"}

Hello
Hello
Hello
Hello

Eftersom PowerShell behandlar $null som en explicit platshållare genererar cmdleten ForEach-Object ett värde för $null som för andra objekt som skickas till den.

Exempel 6: Hämta egenskapsvärden

Det här exemplet hämtar värdet för egenskapen Path för alla installerade PowerShell-moduler med parametern MemberName i cmdleten ForEach-Object.

Get-Module -ListAvailable | ForEach-Object -MemberName Path
Get-Module -ListAvailable | foreach Path

Det andra kommandot motsvarar det första. Den använder Foreach alias för cmdleten ForEach-Object och utelämnar namnet på parametern MemberName, vilket är valfritt.

Cmdleten ForEach-Object är användbar för att hämta egenskapsvärden, eftersom den hämtar värdet utan att ändra typen, till skillnad från cmdletarna Format eller cmdleten Select-Object, som ändrar egenskapsvärdetypen.

Exempel 7: Dela upp modulnamn i komponentnamn

Det här exemplet visar tre sätt att dela upp två punktavgränsade modulnamn i sina komponentnamn. Kommandona anropar metoden Split för strängar. De tre kommandona använder olika syntax, men de är likvärdiga och utbytbara. Utdata är desamma för alla tre fallen.

"Microsoft.PowerShell.Core", "Microsoft.PowerShell.Host" |
    ForEach-Object {$_.Split(".")}
"Microsoft.PowerShell.Core", "Microsoft.PowerShell.Host" |
    ForEach-Object -MemberName Split -ArgumentList "."
"Microsoft.PowerShell.Core", "Microsoft.PowerShell.Host" |
    foreach Split "."

Microsoft
PowerShell
Core
Microsoft
PowerShell
Host

Det första kommandot använder den traditionella syntaxen, som innehåller ett skriptblock och den aktuella objektoperatorn $_. Den använder punktsyntaxen för att ange metoden och parenteserna för att omsluta avgränsningsargumentet.

Det andra kommandot använder parametern MemberName för att ange metoden Split och parametern ArgumentList för att identifiera punkten (.) som avgränsare för delning.

Det tredje kommandot använder foreach alias för cmdleten ForEach-Object och utelämnar namnen på parametrarna MemberName och ArgumentList, som är valfria.

Exempel 8: Använda ForEach-Object med två skriptblock

I det här exemplet skickar vi två skriptblock positionligt. Alla skriptblock binder till parametern Process. De behandlas dock som om de hade skickats till parametrarna Begin och Process.

1..2 | ForEach-Object { 'begin' } { 'process' }

begin
process
process

Exempel 9: Använda ForEach-Object med fler än två skriptblock

I det här exemplet skickar vi fyra skriptblock positionligt. Alla skriptblock binder till parametern Process. De behandlas dock som om de hade skickats till parametrarna Begin, Processoch End.

1..2 | ForEach-Object { 'begin' } { 'process A' }  { 'process B' } { 'end' }

begin
process A
process B
process A
process B
end

Not

Det första skriptblocket mappas alltid till det begin blocket, det sista blocket mappas till det end blocket och de två mellanblocken mappas till det process blocket.

Exempel 10: Kör flera skriptblock för varje pipelineobjekt

Som du ser i föregående exempel mappas flera skriptblock som skickas med parametern Process till parametrarna Begin och End. För att undvika den här mappningen måste du ange explicita värden för parametrarna Begin och End.

1..2 | ForEach-Object -Begin $null -Process { 'one' }, { 'two' }, { 'three' } -End $null

one
two
three
one
two
three

Exempel 11: Kör långsamt skript i parallella batchar

Det här exemplet kör ett skriptblock som utvärderar en sträng och viloläge under en sekund.

$Message = "Output:"

1..8 | ForEach-Object -Parallel {
    "$Using:Message $_"
    Start-Sleep 1
} -ThrottleLimit 4

Output: 1
Output: 2
Output: 3
Output: 4
Output: 5
Output: 6
Output: 7
Output: 8

Parametervärdet ThrottleLimit anges till 4 så att indata bearbetas i batchar om fyra. Den Using: omfångsmodifieraren används för att skicka $Message-variabeln till varje parallellt skriptblock.

Exempel 12: Hämta loggposter parallellt

Det här exemplet hämtar 50 000 loggposter från 5 systemloggar på en lokal Windows-dator.

$logNames = 'Security', 'Application', 'System', 'Windows PowerShell',
    'Microsoft-Windows-Store/Operational'

$logEntries = $logNames | ForEach-Object -Parallel {
    Get-WinEvent -LogName $_ -MaxEvents 10000
} -ThrottleLimit 5

$logEntries.Count

50000

Parametern Parallel anger skriptblocket som körs parallellt för varje indataloggnamn. Parametern ThrottleLimit ser till att alla fem skriptblock körs samtidigt.

Exempel 13: Kör parallellt som ett jobb

Det här exemplet skapar ett jobb som kör ett skriptblock parallellt, två i taget.

PS> $job = 1..10 | ForEach-Object -Parallel {
    "Output: $_"
    Start-Sleep 1
} -ThrottleLimit 2 -AsJob

PS> $job

Id     Name            PSJobTypeName   State         HasMoreData     Location      Command
--     ----            -------------   -----         -----------     --------      -------
23     Job23           PSTaskJob       Running       True            PowerShell    …

PS> $job.ChildJobs

Id     Name            PSJobTypeName   State         HasMoreData     Location      Command
--     ----            -------------   -----         -----------     --------      -------
24     Job24           PSTaskChildJob  Completed     True            PowerShell    …
25     Job25           PSTaskChildJob  Completed     True            PowerShell    …
26     Job26           PSTaskChildJob  Running       True            PowerShell    …
27     Job27           PSTaskChildJob  Running       True            PowerShell    …
28     Job28           PSTaskChildJob  NotStarted    False           PowerShell    …
29     Job29           PSTaskChildJob  NotStarted    False           PowerShell    …
30     Job30           PSTaskChildJob  NotStarted    False           PowerShell    …
31     Job31           PSTaskChildJob  NotStarted    False           PowerShell    …
32     Job32           PSTaskChildJob  NotStarted    False           PowerShell    …
33     Job33           PSTaskChildJob  NotStarted    False           PowerShell    …

Parametern ThrottleLimit begränsar antalet parallella skriptblock som körs åt gången. Parametern AsJob gör att cmdleten ForEach-Object returnerar ett jobbobjekt i stället för att strömma utdata till konsolen. Variabeln $job tar emot jobbobjektet som samlar in utdata och övervakar körningstillståndet. Egenskapen $job.ChildJobs innehåller de underordnade jobb som kör de parallella skriptblocken.

Exempel 14: Använda trådsäkra variabelreferenser

Det här exemplet anropar skriptblock parallellt för att samla in unikt namngivna processobjekt.

$threadSafeDictionary = [System.Collections.Concurrent.ConcurrentDictionary[string,object]]::new()
Get-Process | ForEach-Object -Parallel {
    $dict = $Using:threadSafeDictionary
    $dict.TryAdd($_.ProcessName, $_)
}

$threadSafeDictionary["pwsh"]

NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     82    82.87     130.85      15.55    2808   2 pwsh

En enda instans av ett ConcurrentDictionary--objekt skickas till varje skriptblock för att samla in objekten. Eftersom ConcurrentDictionary är trådsäker är det säkert att ändras av varje parallellt skript. Ett icke-trådsäkert objekt, till exempel System.Collections.Generic.Dictionary, skulle inte vara säkert att använda här.

Not

Det här exemplet är en ineffektiv användning av parametern Parallel. Skriptet lägger till indataobjektet i ett samtidigt ordlisteobjekt. Det är trivialt och inte värt att anropa varje skript i en separat tråd. Att köra ForEach-Object utan växeln Parallel är effektivare och snabbare. Det här exemplet är bara avsett att visa hur du använder trådsäkra variabler.

Exempel 15: Skriva fel med parallell körning

Det här exemplet skriver till felströmmen parallellt, där ordningen på skriftliga fel är slumpmässig.

1..3 | ForEach-Object -Parallel {
    Write-Error "Error: $_"
}

Write-Error: Error: 1
Write-Error: Error: 3
Write-Error: Error: 2

Exempel 16: Avsluta fel vid parallell körning

Det här exemplet visar ett avslutande fel i en parallell skriptblockering som körs parallellt.

1..5 | ForEach-Object -Parallel {
    if ($_ -eq 3)
    {
        throw "Terminating Error: $_"
    }

    Write-Output "Output: $_"
}

Exception: Terminating Error: 3
Output: 1
Output: 4
Output: 2
Output: 5

Output: 3 skrivs aldrig eftersom den parallella scriptblock för iterationen avslutades.

Not

PipelineVariable vanliga parametervariabler stöds inte i ForEach-Object -Parallel scenarier även med Using: omfångsmodifierare.

Exempel 17: Skicka variabler i kapslat parallellt skript ScriptBlockSet

Du kan skapa en variabel utanför en ForEach-Object -Parallel begränsad skriptblockering och använda den i skriptblocket med Using: omfångsmodifierare.

$test1 = 'TestA'
1..2 | ForEach-Object -Parallel {
    $Using:test1
}

TestA
TestA

# You CANNOT create a variable inside a scoped scriptblock
# to be used in a nested foreach parallel scriptblock.
$test1 = 'TestA'
1..2 | ForEach-Object -Parallel {
    $Using:test1
    $test2 = 'TestB'
    1..2 | ForEach-Object -Parallel {
        $Using:test2
    }
}

Line |
   2 |  1..2 | ForEach-Object -Parallel {
     |         ~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The value of the using variable '$Using:test2' can't be retrieved because it has
     | not been set in the local session.

Det kapslade skriptblocket kan inte komma åt variabeln $test2 och ett fel utlöses.

Exempel 18: Skapa flera jobb som kör skript parallellt

Parametern ThrottleLimit begränsar antalet parallella skript som körs under varje instans av ForEach-Object -Parallel. Det begränsar inte antalet jobb som kan skapas när du använder parametern AsJob. Eftersom jobben körs samtidigt är det möjligt att skapa flera parallella jobb, var och en körs upp till begränsningsgränsen för antalet samtidiga skriptblock.

$jobs = for ($i=0; $i -lt 10; $i++) {
    1..10 | ForEach-Object -Parallel {
        ./RunMyScript.ps1
    } -AsJob -ThrottleLimit 5
}

$jobs | Receive-Job -Wait

Det här exemplet skapar 10 jobb som körs. Varje jobb kör inte fler än 5 skript samtidigt. Det totala antalet instanser som körs samtidigt är begränsat till 50 (10 jobb gånger ThrottleLimit av 5).

Parametrar

-ArgumentList

Anger en matris med argument till ett metodanrop. Mer information om beteendet för ArgumentListfinns i about_Splatting.

Den här parametern introducerades i Windows PowerShell 3.0.

Typ:Object[]
Alias:Args
Position:Named
Standardvärde:None
Obligatorisk:False
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-AsJob

Gör att det parallella anropet körs som ett PowerShell-jobb. Ett enskilt jobbobjekt returneras i stället för utdata från skriptblocken som körs. Jobbobjektet innehåller underordnade jobb för varje parallellt skriptblock som körs. Du kan använda jobbobjektet med någon av PowerShell-jobb-cmdletarna för att se körningstillståndet och hämta data.

Den här parametern introducerades i PowerShell 7.0.

Typ:SwitchParameter
Position:Named
Standardvärde:None
Obligatorisk:False
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-Begin

Anger ett skriptblock som körs innan den här cmdleten bearbetar indataobjekt. Det här skriptblocket körs bara en gång för hela pipelinen. Mer information om blocket begin finns i about_Functions.

Typ:ScriptBlock
Position:Named
Standardvärde:None
Obligatorisk:False
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-Confirm

Uppmanar dig att bekräfta innan du kör cmdleten.

Typ:SwitchParameter
Alias:cf
Position:Named
Standardvärde:False
Obligatorisk:False
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-End

Anger ett skriptblock som körs efter att den här cmdleten bearbetar alla indataobjekt. Det här skriptblocket körs bara en gång för hela pipelinen. Mer information om blocket end finns i about_Functions.

Typ:ScriptBlock
Position:Named
Standardvärde:None
Obligatorisk:False
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-InputObject

Anger indataobjekten. ForEach-Object kör skriptblocket eller åtgärdssatsen för varje indataobjekt. Ange en variabel som innehåller objekten eller skriv ett kommando eller uttryck som hämtar objekten.

När du använder parametern InputObject med ForEach-Object, i stället för att skicka kommandoresultat till ForEach-Object, behandlas värdet InputObject som ett enda objekt. Detta gäller även om värdet är en samling som är resultatet av ett kommando, till exempel -InputObject (Get-Process). Eftersom InputObject- inte kan returnera enskilda egenskaper från en matris eller samling objekt rekommenderar vi att om du använder ForEach-Object för att utföra åtgärder på en samling objekt för objekt som har specifika värden i definierade egenskaper, använder du ForEach-Object i pipelinen, som du ser i exemplen i det här avsnittet.

Typ:PSObject
Position:Named
Standardvärde:None
Obligatorisk:False
Godkänn pipeline-indata:True
Godkänn jokertecken:False

-MemberName

Anger namnet på medlemsegenskapen som ska hämtas eller vilken medlemsmetod som ska anropas. Medlemmarna måste vara instansmedlemmar, inte statiska medlemmar.

Jokertecken tillåts, men fungerar bara om den resulterande strängen matchas till ett unikt värde. Om du till exempel kör Get-Process | foreach -MemberName *Namematchar jokertecknet fler än en medlem, vilket gör att kommandot misslyckas.

Den här parametern introducerades i Windows PowerShell 3.0.

Typ:String
Position:0
Standardvärde:None
Obligatorisk:True
Godkänn pipeline-indata:False
Godkänn jokertecken:True

-Parallel

Anger det skriptblock som ska användas för parallell bearbetning av indataobjekt. Ange ett skriptblock som beskriver åtgärden.

Den här parametern introducerades i PowerShell 7.0.

Typ:ScriptBlock
Position:Named
Standardvärde:None
Obligatorisk:True
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-Process

Anger den åtgärd som utförs på varje indataobjekt. Det här skriptblocket körs för varje objekt i pipelinen. Mer information om blocket process finns i about_Functions.

När du anger flera skriptblock för parametern Process mappas alltid det första skriptblocket till begin-blocket. Om det bara finns två skriptblock mappas det andra blocket till det process blocket. Om det finns tre eller flera skriptblock mappas det första skriptblocket alltid till det begin blocket, det sista blocket mappas till det end blocket och de mellersta blocken mappas till det process blocket.

Typ:ScriptBlock[]
Position:0
Standardvärde:None
Obligatorisk:True
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-RemainingScripts

Anger alla skriptblock som inte tas av parametern Process.

Den här parametern introducerades i Windows PowerShell 3.0.

Typ:ScriptBlock[]
Position:Named
Standardvärde:None
Obligatorisk:False
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-ThrottleLimit

Anger antalet skriptblock som körs parallellt. Indataobjekt blockeras tills antalet skriptblock som körs understiger ThrottleLimit-. Standardvärdet är 5.

Parametern ThrottleLimit begränsar antalet parallella skript som körs under varje instans av ForEach-Object -Parallel. Det begränsar inte antalet jobb som kan skapas när du använder parametern AsJob. Eftersom jobben körs samtidigt är det möjligt att skapa ett antal parallella jobb, var och en körs upp till begränsningsgränsen för antalet samtidiga skriptblock.

Den här parametern introducerades i PowerShell 7.0.

Typ:Int32
Position:Named
Standardvärde:5
Obligatorisk:False
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-TimeoutSeconds

Anger hur många sekunder som ska vänta tills alla indata bearbetas parallellt. Efter den angivna tidsgränstiden stoppas alla skript som körs. Och eventuella återstående indataobjekt som ska bearbetas ignoreras. Standardvärdet för 0 inaktiverar tidsgränsen och ForEach-Object -Parallel kan köras på obestämd tid. Om du skriver Ctrl+C- på kommandoraden stoppas ett ForEach-Object -Parallel kommando som körs. Den här parametern kan inte användas tillsammans med parametern AsJob.

Den här parametern introducerades i PowerShell 7.0.

Typ:Int32
Position:Named
Standardvärde:0
Obligatorisk:False
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-UseNewRunspace

Gör att det parallella anropet skapar en ny runspace för varje loop-iteration i stället för att återanvända runspaces från runspace-poolen.

Den här parametern introducerades i PowerShell 7.1

Typ:SwitchParameter
Position:Named
Standardvärde:False
Obligatorisk:False
Godkänn pipeline-indata:False
Godkänn jokertecken:False

-WhatIf

Visar vad som skulle hända om cmdleten körs. Cmdleten körs inte.

Typ:SwitchParameter
Alias:wi
Position:Named
Standardvärde:False
Obligatorisk:False
Godkänn pipeline-indata:False
Godkänn jokertecken:False

Indata

PSObject

Du kan skicka valfritt objekt till den här cmdleten.

Utdata

PSObject

Den här cmdleten returnerar objekt som bestäms av indata.

Kommentarer

PowerShell innehåller följande alias för ForEach-Object:

  • Alla plattformar:
    • %
    • foreach

Cmdleten ForEach-Object fungerar ungefär som foreach-instruktionen, förutom att du inte kan skicka indata till en foreach-instruktion. Mer information om foreach-instruktionen finns i about_Foreach.

Från och med PowerShell 4.0 lades Where och ForEach metoder till för användning med samlingar. Du kan läsa mer om dessa nya metoder här about_Arrays

Använda ForEach-Object -Parallel:

  • ForEach-Object -Parallel kör varje skriptblock i ett nytt runspace. De nya runspaces skapar betydligt mer omkostnader än att köra ForEach-Object med sekventiell bearbetning. Det är viktigt att använda Parallell där belastningen för att köra parallellt är liten jämfört med det arbete som skriptblocket utför. Till exempel:

    • Beräkningsintensiva skript på datorer med flera kärnor
    • Skript som ägnar tid åt att vänta på resultat eller utföra filåtgärder

    Om du använder parametern Parallel kan skript köras mycket långsammare än normalt. Särskilt om parallella skript är triviala. Experimentera med Parallel för att upptäcka var det kan vara fördelaktigt.

  • När du kör parallellt kan objekt som är dekorerade med ScriptProperties eller ScriptMethods inte garanteras fungera korrekt om de körs i ett annat körningsutrymme än skripten ursprungligen var kopplade till dem.

    Scriptblock-anrop försöker alltid köras i dess hem runspace, oavsett var det faktiskt anropas. Men ForEach-Object -Parallel skapar tillfälliga runspaces som tas bort efter användning, så det finns ingen runspace för skripten att köra i längre.

    Det här beteendet kan fungera så länge hem runspace fortfarande finns. Du kanske dock inte får önskat resultat om skriptet är beroende av externa variabler som bara finns i anroparens runspace och inte start runspace.

  • Icke-avslutande fel skrivs till cmdlet-felströmmen när de inträffar parallellt med skriptblockering. Eftersom körningsordningen för parallell scriptblock är icke-deterministisk är ordningen i vilken felen visas i felströmmen slumpmässig. På samma sätt skrivs meddelanden som skrivs till andra dataströmmar, till exempel varning, utförlig eller information, till dessa dataströmmar i en obestämd ordning.

    Avslutande fel, till exempel undantag, avslutar den enskilda parallella instansen av skriptblocken där de inträffar. Ett avslutande fel i en skriptblockering kan inte orsaka att ForEach-Object cmdlet avslutas. De andra skriptblocken, som körs parallellt, fortsätter att köras om de inte också stöter på ett avslutande fel. Det avslutande felet skrivs till feldataströmmen som en ErrorRecord- med en FullyQualifiedErrorId för PSTaskException. Avslutande fel kan konverteras till icke-avslutande fel med hjälp av PowerShell-try/catch eller trap block.

  • PipelineVariable vanliga parametervariabler inte stöds i parallella scenarier även med Using: omfångsmodifierare.

    Viktig

    Parameteruppsättningen ForEach-Object -Parallel kör skriptblock parallellt på separata processtrådar. Med Using:-modifieraren kan du skicka variabelreferenser från cmdlet-anropstråden till varje skriptblocktråd som körs. Eftersom skriptblocken körs i olika trådar måste objektvariablerna som skickas med referens användas på ett säkert sätt. Vanligtvis är det säkert att läsa från refererade objekt som inte ändras. Om du behöver ändra objekttillståndet måste du använda trådsäkra objekt, till exempel .NET System.Collection.Concurrent typer (se exempel 14).