Realiza una operación contra cada elemento de una colección de objetos de entrada.
Sintaxis
ForEach-Object <ScriptBlock> >]
ForEach-Object <String> >]
ForEach-Object -Parallel <scriptblock>
Descripción
El cmdlet ForEach-Object
realiza una operación en cada elemento de una colección de objetos de entrada. Los objetos de entrada pueden ser canalizados al cmdlet o especificados mediante el parámetro InputObject.
A partir de Windows PowerShell 3.0, hay dos formas diferentes de construir un ForEach-Object
comando.
-
Bloque de script. Puede utilizar un bloque de script para especificar la operación. Dentro del bloque de script,utilice la variable
$_
para representar el objeto actual. El bloque de script es el valor del parámetroProcess. El bloque de script puede contener cualquier script de PowerShell.Por ejemplo, el siguiente comando obtiene el valor de la propiedad ProcessName de cada proceso del equipo.
Get-Process | ForEach-Object {$_.ProcessName}
ForEach-Object
soporta elbegin
process
, yend
bloques como se describe enabout_functions.Nota
Los bloques de script se ejecutan en el ámbito de la persona que llama. Por lo tanto, los bloques tienen acceso a las variables en ese ámbito y pueden crear nuevas variables que persisten en ese ámbito después de que el cmdlet se complete.
-
Declaración de operación. También puede escribir una declaración de operación, que es mucho más parecida al lenguaje natural. Puede utilizar la declaración de operación para especificar un valor de propiedad o llamar a un método. Las declaraciones de operación se introdujeron en Windows PowerShell 3.0.
Por ejemplo, el siguiente comando también obtiene el valor de la propiedad ProcessName de cadaproceso en el equipo.
Get-Process | ForEach-Object ProcessName
Bloque de script de ejecución paralela. A partir de PowerShell 7.0, está disponible un tercer conjunto de parámetros que ejecuta cada bloque de script en paralelo. El parámetro ThrottleLimit limita el número de scripts paralelos que se ejecutan a la vez. Como antes, utilice la variable $_
para representar el objeto de entrada actual en el bloque de script. Utilice la palabra clave $using:
para pasar referencias de variables al script en ejecución.
En PowerShell 7, se crea un nuevo espacio de ejecución para cada iteración de bucle para garantizar el máximo aislamiento.Esto puede suponer un gran impacto en el rendimiento y los recursos si el trabajo que está realizando es pequeño en comparación con la creación de nuevos espacios de ejecución o si hay muchas iteraciones que realizan un trabajo significativo. A partir de PowerShell 7.1, los espacios de ejecución de un grupo de espacios de ejecución se reutilizan por defecto. El tamaño de la reserva de espacios de ejecución se especifica mediante el parámetro ThrottleLimit. El tamaño predeterminado del grupo de espacios de ejecución es de 5. Aún puede crear un nuevo espacio de ejecución para cada iteración utilizando el parámetro UseNewRunspace.
Por defecto, los bloques de scripts paralelos utilizan el directorio de trabajo actual del llamador que inició las tareas paralelas.
Los errores que no terminan se escriben en el flujo de errores del cmdlet a medida que se producen en los bloques de scripts de ejecución paralelos. Dado que no se puede determinar el orden de ejecución de los bloques de script paralelos, el orden en el que aparecen los errores en el flujo de errores es aleatorio. Del mismo modo, los mensajes que se escriben en otros flujos de datos, como los de advertencia, verbose o información, se escriben en esos flujos de datos en un orden indeterminado.
Los errores de terminación, como las excepciones, terminan la instancia paralela individual de los bloques de script en los que se producen. Un error de terminación en un bloque de secuencia de comandos no puede causar la terminación del cmdlet Foreach-Object
. Los otros bloques de script, que se ejecutan en paralelo, continúan ejecutándose a menos que también encuentren un error de terminación. El error de terminación se escribe en el flujo de datos de error como un ErrorRecord con un FullyQualifiedErrorId de PSTaskException
.Los errores de terminación se pueden convertir en errores de no terminación utilizando los bloques try/catch o trap de PowerShell.
Ejemplos
Ejemplo 1: Dividir enteros en un array
Este ejemplo toma un array de tres enteros y divide cada uno de ellos por 1024.
30000, 56798, 12432 | ForEach-Object -Process {$_/1024}29.29687555.46679687512.140625
Ejemplo 2: Obtener la longitud de todos los archivos de un directorio
Este ejemplo procesa los archivos y directorios del directorio de instalación de PowerShell $PSHOME
.
Get-ChildItem $PSHOME | ForEach-Object -Process {if (!$_.PSIsContainer) {$_.Name; $_.Length / 1024; " " }}
Si el objeto no es un directorio, el bloque de script obtiene el nombre del archivo, divide el valor de su propiedad Length entre 1024 y añade un espacio (» «) para separarlo de la siguiente entrada. Elecmdlet utiliza la propiedad PSISContainer para determinar si un objeto es un directorio.
Ejemplo 3: Operar con los eventos más recientes del Sistema
Este ejemplo escribe los 1000 eventos más recientes del registro de eventos del Sistema en un archivo de texto. La hora actual se muestra antes y después de procesar los eventos.
$Events = Get-EventLog -LogName System -Newest 1000$events | ForEach-Object -Begin {Get-Date} -Process {Out-File -FilePath Events.txt -Append -InputObject $_.Message} -End {Get-Date}
Get-EventLog
obtiene los 1000 eventos más recientes del registro de eventos del Sistema y los almacena en la variable$Events
$Events
se envía al cmdlet ForEach-Object
. El parámetro Begin muestra la fecha y la hora actuales. A continuación, el parámetro Process utiliza el cmdlet Out-File
para crear un archivo de texto llamado events.txt y almacena la propiedad message de cada uno de los eventos en ese archivo. Por último, el parámetro End se utiliza para mostrar la fecha y la hora después de que todo elprocesamiento haya finalizado.
Ejemplo 4: Cambiar el valor de una clave del Registro
Este ejemplo cambia el valor de la entrada del registro RemotePath en todas las subclaves bajo laHKCU:\Network
clave a texto en mayúsculas.
Get-ItemProperty -Path HKCU:\Network\* | ForEach-Object {Set-ItemProperty -Path $_.PSPath -Name RemotePath -Value $_.RemotePath.ToUpper();}
Puede utilizar este formato para cambiar la forma o el contenido del valor de una entrada del registro.
Cada subclave de la clave Network representa una unidad de red asignada que se reconecta al iniciar sesión. La entradaRemotePath contiene la ruta UNC de la unidad conectada. Por ejemplo, si asigna la unidad E:a \\Server\Share
, se crea una subclave E en HKCU:\Network
con el valor RemotePathregistry establecido en \\Server\Share
.
El comando utiliza el cmdlet Get-ItemProperty
para obtener todas las subclaves de la clave Red y el cmdlet Set-ItemProperty
para cambiar el valor de la entrada del registro RemotePath en cada clave.En el comando Set-ItemProperty
, la ruta es el valor de la propiedad PSPath de la clave del registro. Esta es una propiedad del objeto de Microsoft .NET Framework que representa la clave del registro, no la entrada del registro. El comando utiliza el método ToUpper() del valor RemotePath, que es una cadena (REG_SZ).
Debido a que Set-ItemProperty
está cambiando la propiedad de cada clave, se requiere el cmdlet ForEach-Object
para acceder a la propiedad.
Ejemplo 5: Utilizar la variable automática $Null
Este ejemplo muestra el efecto de canalizar la variable automática $Null
al cmdlet ForEach-Object
.
1, 2, $null, 4 | ForEach-Object {"Hello"}HelloHelloHelloHello
Debido a que PowerShell trata a null como un marcador de posición explícito, el cmdlet ForEach-Object
genera un valor para $Null
, al igual que lo hace para otros objetos que se le canalizan.
Ejemplo 6: Obtener valores de propiedades
Este ejemplo obtiene el valor de la propiedad Path de todos los módulos PowerShell instalados utilizando el parámetro MemberName del cmdlet ForEach-Object
.
Get-Module -ListAvailable | ForEach-Object -MemberName PathGet-Module -ListAvailable | Foreach Path
El segundo comando es equivalente al primero. Utiliza el Foreach
alias del ForEach-Object
cmdlet y omite el nombre del parámetro MemberName, que es opcional.
El cmdlet ForEach-Object
es útil para obtener valores de propiedades, ya que obtiene el valor sin cambiar el tipo, a diferencia de los cmdlets Format o el cmdlet Select-Object
, que cambian el tipo de valor de la propiedad.
Ejemplo 7: Dividir nombres de módulos en nombres de componentes
Este ejemplo muestra tres formas de dividir dos nombres de módulos separados por puntos en sus nombres de componentes.
"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 "."MicrosoftPowerShellCoreMicrosoftPowerShellHost
Los comandos llaman al método Split de cadenas. Los tres comandos utilizan una sintaxis diferente, pero son equivalentes e intercambiables.
El primer comando utiliza la sintaxis tradicional, que incluye un bloque de script y el objectoperador actual $_
. Utiliza la sintaxis de punto para especificar el método y paréntesis para encerrar el argumento delimitador.
El segundo comando utiliza el parámetro MemberName para especificar el método Split y el parámetroArgumentName para identificar el punto («.») como delimitador de división.
El tercer comando utiliza el alias Foreach del cmdlet ForEach-Object
y omite los nombres de los parámetros MemberName y ArgumentList, que son opcionales.
Ejemplo 8: Uso de ForEach-Object con dos bloques de script
En este ejemplo, pasamos dos bloques de script posicionalmente. Todos los bloques de script se vinculan al parámetroProcess. Sin embargo, se tratan como si se hubieran pasado a los parámetros Begin yProcess.
1..2 | ForEach-Object { 'begin' } { 'process' }beginprocessprocess
Ejemplo 9: Uso de ForEach-Object con más de dos bloques de script
En este ejemplo, pasamos dos bloques de script posicionalmente. Todos los bloques de script se vinculan al parámetroProcess. Sin embargo, se tratan como si se hubieran pasado a los parámetros Begin,Process y End.
1..2 | ForEach-Object { 'begin' } { 'process A' } { 'process B' } { 'end' }beginprocess Aprocess Bprocess Aprocess Bend
El primer bloque de script se asigna siempre al bloque begin
, el último bloque se asigna al bloque end
, y los bloques intermedios se asignan todos al bloque process
.
Ejemplo 10: Ejecutar múltiples bloques de script para cada elemento de la tubería
Como se muestra en el ejemplo anterior, múltiples bloques de script pasados usando el parámetro Process se mapean a los parámetros Begin y End. Para evitar este mapeo, debe proporcionar valores explícitos para los parámetros Begin y End.
1..2 | ForEach-Object -Begin $null -Process { 'one' }, { 'two' }, { 'three' } -End $nullonetwothreeonetwothree
Ejemplo 11: Ejecutar un script lento en lotes paralelos
Este ejemplo ejecuta un bloque de script simple que evalúa una cadena y duerme durante un segundo.
$Message = "Output:"1..8 | ForEach-Object -Parallel { "$using:Message $_" Start-Sleep 1} -ThrottleLimit 4Output: 1Output: 2Output: 3Output: 4Output: 5Output: 6Output: 7Output: 8
El valor del parámetro ThrottleLimit se establece en 4 para que la entrada se procese en lotes de cuatro.La palabra clave $using:
se utiliza para pasar la variable $Message
a cada bloque de script paralelo.
Ejemplo 12: Recuperar entradas de registro en paralelo
Este ejemplo recupera 50.000 entradas de registro de 5 registros del sistema en una máquina Windows local.
$logNames = 'Security','Application','System','Windows PowerShell','Microsoft-Windows-Store/Operational'$logEntries = $logNames | ForEach-Object -Parallel { Get-WinEvent -LogName $_ -MaxEvents 10000} -ThrottleLimit 5$logEntries.Count50000
El parámetro Parallel especifica el bloque de script que se ejecuta en paralelo para cada nombre de registro de entrada. El parámetro ThrottleLimit asegura que los cinco bloques de script se ejecuten al mismo tiempo.
Ejemplo 13: Ejecutar en paralelo como un trabajo
Este ejemplo ejecuta un simple bloque de script en paralelo, creando dos trabajos en segundo plano a la vez.
$job = 1..10 | ForEach-Object -Parallel { "Output: $_" Start-Sleep 1} -ThrottleLimit 2 -AsJob$job | Receive-Job -WaitOutput: 1Output: 2Output: 3Output: 4Output: 5Output: 6Output: 7Output: 8Output: 9Output: 10
La variable $job
recibe el objeto de trabajo que recoge los datos de salida y monitoriza el estado de ejecución.El objeto de trabajo se canaliza a Receive-Job
con el parámetro Wait switch. Y esto transmite la salida a la consola, igual que si ForEach-Object -Parallel
se ejecutara sin AsJob.
Ejemplo 14: Uso de referencias de variables seguras para hilos
Este ejemplo invoca bloques de scripts en paralelo para recopilar objetos Process con nombres únicos.
$threadSafeDictionary = ]::new()Get-Process | ForEach-Object -Parallel { $dict = $using:threadSafeDictionary $dict.TryAdd($_.ProcessName, $_)}$threadSafeDictionaryNPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName ------ ----- ----- ------ -- -- ----------- 82 82.87 130.85 15.55 2808 2 pwsh
Se pasa una única instancia de un objeto ConcurrentDictionary a cada bloque de script para recoger los objetos. Dado que el ConcurrentDictionary es seguro para los hilos, es seguro para ser modificado por cada script paralelo. Un objeto no seguro para hilos, como System.Collections.Generic.Dictionary, no sería seguro para usar aquí.
Nota
Este ejemplo es un uso muy ineficiente del parámetro Parallel. El script simplemente añade el objeto de entrada a un objeto diccionario concurrente. Es trivial y no vale la pena la sobrecarga de invocar cada script en un hilo separado. Ejecutar ForEach-Object
normalmente sin el Parallelswitch es mucho más eficiente y rápido. Este ejemplo sólo pretende demostrar cómo utilizar variables seguras para los hilos.
Ejemplo 15: Escritura de errores con ejecución en paralelo
Este ejemplo escribe en el flujo de errores en paralelo, donde el orden de los errores escritos es aleatorio.
1..3 | ForEach-Object -Parallel { Write-Error "Error: $_"}Write-Error: Error: 1Write-Error: Error: 3Write-Error: Error: 2
Ejemplo 16: Terminación de errores en ejecución paralela
Este ejemplo demuestra un error de terminación en un bloque de script de ejecución paralela.
1..5 | ForEach-Object -Parallel { if ($_ -eq 3) { throw "Terminating Error: $_" } Write-Output "Output: $_"}Exception: Terminating Error: 3Output: 1Output: 4Output: 2Output: 5
Output: 3
nunca se escribe porque el bloque de script paralelo para esa iteración se terminó.
Ejemplo 17: Pasar variables en ScriptBlockSet de scripts paralelos anidados
Puedes crear una variable fuera de un Foreach-Object -Parallel
scoped scriptblock y usarla dentro del scriptblock con la palabra clave $using
.
$test1 = 'TestA'1..2 | Foreach-Object -Parallel { $using:test1}TestATestA# 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' cannot be retrieved because it has not been set in the local session.
El bloque de script anidado no puede acceder a la variable $test2
y se lanza un error.
Parámetros
Especifica un array de argumentos para una llamada a un método. Para obtener más información sobre el comportamiento deArgumentList, consulte about_Splatting.
Este parámetro se introdujo en Windows PowerShell 3.0.
Tipo: | Objeto |
Aliases: | Args |
Posición: | Nombre | Valor por defecto: | Ninguna | Aceptar entrada de tuberías: | Falso |
Aceptar caracteres comodín: | Falso |
Este parámetro se introdujo en PowerShell 7.0.
Tipo: | SwitchParameter | Posición: | Nombre | Valor por defecto: | Ninguna | Aceptar entrada de tuberías: | False |
Aceptar caracteres comodín: | False |
begin
, consulteacerca de_Funciones.
Tipo: | BloqueScript | Posición: | Nombre | Valor por defecto: | Ninguna | Aceptar entrada de tuberías: | Falso |
Aceptar caracteres comodín: | Falso |
Tipo: | SwitchParameter | Alias: | cf |
Posición: | Nombrado | Valor por defecto: | Falso |
Aceptar entrada de tuberías: | False |
Aceptar caracteres comodín: | False |
end
, consulteabout_Functions.
Tipo: | BloqueScript | Posición: | Nombre | Valor por defecto: | Ninguna | Aceptar entrada de tuberías: | Falso |
Aceptar caracteres comodín: | Falso |
Especifica los objetos de entrada. ForEach-Object
ejecuta el bloque de script o la sentencia de operación en cada objetoinput. Introduzca una variable que contenga los objetos o escriba un comando o una expresión que obtenga los objetos.
Cuando utilice el parámetro InputObject con ForEach-Object
, en lugar de canalizar los resultados del comando a ForEach-Object
, el valor de InputObject se trata como un único objeto. Esto es cierto incluso si el valor es una colección que es el resultado de un comando, como -InputObject (Get-Process)
.Debido a que InputObject no puede devolver propiedades individuales de una matriz o colección de objetos, recomendamos que si utiliza ForEach-Object
para realizar operaciones en una colección de objetos para aquellos objetos que tienen valores específicos en propiedades definidas, utilice ForEach-Object
en la línea de producción, como se muestra en los ejemplos de este tema.
Tipo: | PSObject | Posición: | Nombre | Valor por defecto: | Ninguna | Acepta entrada de tuberías: | Verdadero |
Acepta caracteres comodín: | Falso |
Especifica la propiedad a obtener o el método a llamar.
Se permiten caracteres comodín, pero sólo funcionan si la cadena resultante resuelve un valor único.Por ejemplo, si ejecuta Get-Process | ForEach -MemberName *Name
, el patrón comodín coincide con más de un miembro haciendo que el comando falle.
Este parámetro se introdujo en Windows PowerShell 3.0.
Tipo: | String | Posición: | 0 | Valor por defecto: | Ninguno | Aceptar entrada de tuberías: | Falso |
Aceptar caracteres comodín: | Verdadero |
Este parámetro se introdujo en PowerShell 7.0.
Tipo: | Bloque de script |
Posición: | Nombre | Valor por defecto: | Ninguna | Aceptar entrada de tuberías: | Falso |
Aceptar caracteres comodín: | Falso |
process
, consulteacerca de_Funciones.
Cuando proporciona varios bloques de script al parámetro Proceso, el primer bloque de script siempre se asigna al bloque begin
. Si sólo hay dos bloques de script, el segundo bloque se asigna al bloque process
. Si hay tres o más bloques de script, el primer bloque de script siempre se asigna al bloque begin
, el último bloque se asigna al bloque end
, y los bloques intermedios se asignan al bloque process
.
Tipo: | ScriptBlock | Posición: | 0 | Valor por defecto: | Ninguna | Aceptar entrada de tuberías: | False |
Aceptar caracteres comodín: | False |
Este parámetro se introdujo en Windows PowerShell 3.0.
Tipo: | Bloque de script | Posición: | Nombre | Valor por defecto: | Ninguna | Aceptar entrada de tuberías: | Falso |
Aceptar caracteres comodín: | Falso |
5
.
Este parámetro se introdujo en PowerShell 7.0.
Tipo: | Int32 | Posición: | Nombrado | Valor por defecto: | 5 | Acepta entrada de tuberías: | Falso |
Aceptar caracteres comodín: | Falso |
Especifica el número de segundos que hay que esperar para que toda la entrada se procese en paralelo. Después del tiempo de espera especificado, todos los scripts en ejecución se detienen. Y cualquier objeto de entrada restante para serprocesado es ignorado. El valor por defecto de 0
desactiva el tiempo de espera, y ForEach-Object -Parallel
puede ejecutarse indefinidamente. Al escribir Ctrl+C en la línea de comandos se detiene un comandoForEach-Object -Parallel
en ejecución. Este parámetro no puede utilizarse junto con el parámetro AsJob.
Este parámetro se introdujo en PowerShell 7.0.
Tipo: | Int32 | Posición: | Nombrado | Valor por defecto: | 0 | Aceptar entrada de tuberías: | False |
Aceptar caracteres comodín: | False |
Tipo: | SwitchParameter | Aliases: | wi |
Posición: | Nombrado | Valor por defecto: | Falso |
Aceptar entrada de tuberías: | False |
Aceptar caracteres comodín: | False |
Entradas
PSObject
Puede canalizar cualquier objeto a este cmdlet.
Salidas
PSObject
Este cmdlet devuelve objetos determinados por la entrada.
Notas
-
El cmdlet
ForEach-Object
funciona de forma muy parecida a la sentencia Foreach, excepto que no se pueden canalizar entradas a una sentencia Foreach. Para obtener más información sobre la sentencia Foreach, consulte about_Foreach. -
A partir de PowerShell 4.0, se añadieron los métodos
Where
yForEach
para su uso con colecciones. Puedes leer más sobre estos nuevos métodos aquí about_arrays - Secuencias de comandos de cálculo intensivo en máquinas multinúcleo
- Secuencias de comandos que pasan tiempo esperando resultados o haciendo operaciones de archivo
- Comparar-Objeto
- Donde-Objeto
- Agrupar-Objeto
- Medir-Objeto
- Nuevo-Objeto
- Seleccionar-Objeto
- Objeto-Sort
- Objeto-Tee
El conjunto de parámetros ForEach-Object -Parallel
utiliza la API interna de PowerShell para ejecutar cada bloque de script. Esto supone una sobrecarga significativamente mayor que ejecutar ForEach-Object
normalmente con el procesamiento secuencial. Es importante utilizar Paralelo cuando la sobrecarga de ejecutar en paralelo es pequeñacomparada con el trabajo que realiza el bloque de script. Por ejemplo:
Usar el parámetro Parallel puede hacer que las secuencias de comandos se ejecuten mucho más lentamente de lo normal. Especialmente si los scripts paralelos son triviales. Experimente con Parallel para descubrir dónde puede ser beneficioso.
Importante
El conjunto de parámetros ForEach-Object -Parallel
ejecuta bloques de scripts en paralelo en hilos de proceso separados. La palabra clave $using:
permite pasar referencias a variables desde el hilo de invocación del cmdlet a cada hilo de ejecución de los bloques de script. Dado que los bloques de script se ejecutan en diferentes hilos, las variables de objeto pasadas por referencia deben utilizarse de forma segura. Generalmente es seguro leer de objetos referenciados que no cambian. Pero si el estado del objeto se está modificando, entonces debe utilizar objetos seguros para hilos, como los tipos System.Collection.Concurrent de .Net (Ver Ejemplo 11).
- .