Capítulo 4. Bucle y control de flujo
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com
4.0 Introducción
En empiezas a escribir scripts o comandos que interactúan con datos desconocidos, por lo que los conceptos de bucle y control de flujo cobran cada vez más importancia.
Las sentencias y comandos de bucle de PowerShell te permiten realizar una operación (o conjunto de operaciones) sin tener que repetir los propios comandos. Esto incluye, por ejemplo, hacer algo un número determinado de veces, procesar cada elemento de una colección o trabajar hasta que se cumpla una determinada condición.
Las sentencias de control de flujo y comparación de PowerShell te permiten adaptar tu script o comando a datos desconocidos. Te permiten ejecutar comandos en función del valor de esos datos, omitir comandos en función del valor de esos datos, etc.
Juntas, las sentencias de bucle y de control de flujo añaden una gran versatilidad a tu caja de herramientasPowerShell.
4.1 Toma decisiones con operadores de comparación y lógicos
Solución
Utiliza los operadores lógicos de PowerShell para comparar datos y tomar decisiones basadas en ellos:
- Operadores de comparación
-
-eq
,-ne
,-ge
,-gt
,-in
,-notin
,-lt
,-le
,-like
,-notlike
,-match
,-notmatch
,-contains
,-notcontains
,-is
,-isnot
- Operadores lógicos
Para una descripción detallada (y ejemplos) de estos operadores, consulta "Operadores de comparación".
Debate
Los operadores lógicos y de comparación de PowerShell te permiten comparar datos o comprobar si cumplen alguna condición. Un operador compara dos datos (operador binario ) o comprueba un dato (operador unario ). Todos los operadores de comparación son binarios (comparan dos datos), al igual que la mayoría de los operadores lógicos. El único operador lógico unario es el operador -not
, que devuelve el true/false
opuesto a los datos que comprueba.
Los operadores de comparación comparan dos datos y devuelven un resultado que depende del operador de comparación concreto. Por ejemplo, puedes querer comprobar si una colección tiene al menos un determinado número de elementos:
PS > (dir).Count -ge 4 True
o comprobar si una cadena coincide con una expresión regular dada:
PS > "Hello World" -match "H.*World" True
La mayoría de los operadores de comparación también se adaptan al tipo de su entrada. Por ejemplo, cuando los aplicas a datos simples como una cadena, los operadores de comparación -like
y -match
determinan si la cadena coincide con el patrón especificado. Cuando los aplicas a una colección de datos simples, esos mismos operadores de comparación devuelven todos los elementos de esa colección que coincidan con el patrón que proporciones.
Nota
El operador -match
toma como argumento una expresión regular. Uno de los símbolos de expresión regular más comunes es el carácter $
, que representa el final de línea. Sin embargo, ¡el carácter $
también representa el inicio de una variable PowerShell! Para evitar que PowerShell interprete los caracteres como términos de lenguaje o secuencias de escape, coloca la cadena entre comillas simples en lugar de entre comillas dobles:
PS > "Hello World" -match "Hello" True PS > "Hello World" -match 'Hello$' False
Por defecto en, los operadores de comparación de PowerShell no distinguen entre mayúsculas y minúsculas. Para utilizar las versiones que distinguen mayúsculas de minúsculas, ponles como prefijo el carácter c
:
-ceq
,-cne
,-cge
,-cgt
,-cin
,-clt
,-cle
,-clike
,-cnotlike
,-cmatch
,-cnotmatch
,-ccontains
,-cnotcontains
Para una descripción detallada de los operadores de comparación, sus homólogos que distinguen mayúsculas de minúsculas y cómo se adaptan a su entrada, consulta "Operadores de comparación".
Los operadores lógicos combinan sentencias true
o false
y devuelven un resultado que depende del operador lógico específico. Por ejemplo, puede que quieras comprobar si una cadena coincide con el patrón comodín que proporciones y que tiene más de un determinado número de caracteres:
PS > $data = "Hello World" PS > ($data -like "*llo W*") -and ($data.Length -gt 10) True PS > ($data -like "*llo W*") -and ($data.Length -gt 20) False
Algunos de los operadores de comparación incorporan en realidad aspectos de los operadores lógicos. Dado que utilizar el opuesto de una comparación (como -like
) es tan habitual, PowerShell proporciona operadores de comparación (como -notlike
) que te ahorran tener que utilizar explícitamente el operador -not
.
Para una descripción detallada de cada uno de los operadores lógicos, consulta "Operadores de comparación".
Los operadores de comparación y los operadores lógicos (cuando se combinan con sentencias de control de flujo) forman el núcleo de cómo escribimos un script o comando que se adapta a sus datos y a su entrada.
Consulta también "Declaraciones condicionales" para obtener información detallada sobre estas declaraciones.
Para más información sobre los operadores de PowerShell, escribe Get-Help
about_Operators
.
4.2 Ajustar el flujo del script mediante sentencias condicionales
Solución
Utiliza Las sentencias condicionales de PowerShell if
, elseif
, y else
para controlar el flujo de ejecución en tu script.
$temperature
=
90
if
(
$temperature
-le
0
)
{
"Balmy Canadian Summer"
}
elseif
(
$temperature
-le
32
)
{
"Freezing"
}
elseif
(
$temperature
-le
50
)
{
"Cold"
}
elseif
(
$temperature
-le
70
)
{
"Warm"
}
else
{
"Hot"
}
Debate
Las declaraciones condicionales incluyen lo siguiente:
if
declaración-
Ejecuta el bloque de secuencia de comandos que le sigue si su condición se evalúa como
true
elseif
declaración-
Ejecuta el bloque de secuencia de comandos que le sigue si su condición se evalúa como
true
y ninguna de las condiciones de las sentenciasif
oelseif
que le preceden se evalúan comotrue
else
declaración-
Ejecuta el bloque de secuencia de comandos que le sigue si ninguna de las condiciones de las sentencias
if
oelseif
que le preceden se evalúan comotrue
En además de ser útiles para el flujo de control del script, las sentencias condicionales suelen ser una forma útil de asignar datos a una variable. PowerShell lo hace muy fácil permitiéndote asignar los resultados de una sentencia condicional directamente a una variable:
$result
=
if
(
Get-Process
-Name
notepad
)
{
"Running"
}
else
{
"Not running"
}
Para sentencias condicionales muy sencillas como ésta, también puedes utilizar el operador ternario de PowerShell:
$result
=
(
Get-Process
-Name
notepad
*)
?
"Running"
:
"Not running"
Para más información sobre estas sentencias de control de flujo, escribe Get-Help
about_If
.
4.3 Gestionar sentencias condicionales grandes con conmutadores
Solución
Utiliza la sentencia switch
de PowerShell para representar más fácilmente una sentencia condicional grande if
... elseif
... else
.
$temperature
=
20
switch
(
$temperature
)
{
{
$_
-lt
32
}
{
"Below Freezing"
;
break
}
32
{
"Exactly Freezing"
;
break
}
{
$_
-le
50
}
{
"Cold"
;
break
}
{
$_
-le
70
}
{
"Warm"
;
break
}
default
{
"Hot"
}
}
Debate
La sentencia switch
de PowerShell te permite comprobar fácilmente su entrada con un gran número de comparaciones. La sentencia switch
admite varias opciones que te permiten configurar cómo compara PowerShell la entrada con las condiciones, por ejemplo, con un comodín, una expresión regular o incluso un bloque de secuencia de comandos arbitrario. Dado que escanear el texto de un archivo es una tarea muy común, la sentencia switch
de PowerShellpermite hacerlo directamente. Estas adiciones hacen que las sentencias switch
de PowerShell sean mucho más potentes que las de C y C++.
Como otro ejemplo de la declaración switch
en acción, considera cómo determinar el SKU del sistema operativo actual. Por ejemplo, ¿el script se ejecuta en Windows 7 Ultimate? ¿Windows Server Cluster Edition? El cmdlet Get-CimInstance
te permite determinar el SKU del sistema operativo, pero lamentablemente devuelve su resultado como un simple número. Una sentencia switch
te permite asignar estos números a sus equivalentes en inglés basándote en la documentación oficial:
##############################################################################
##
## Get-OperatingSystemSku
##
## From PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Gets the sku information for the current operating system
.EXAMPLE
PS > Get-OperatingSystemSku
Professional with Media Center
#>
param
(
$Sku
=
(
Get-CimInstance
Win32_OperatingSystem
).
OperatingSystemSku
)
Set-StrictMode
-Version
3
switch
(
$Sku
)
{
0
{
"An unknown product"
;
break
;
}
1
{
"Ultimate"
;
break
;
}
2
{
"Home Basic"
;
break
;
}
3
{
"Home Premium"
;
break
;
}
4
{
"Enterprise"
;
break
;
}
5
{
"Home Basic N"
;
break
;
}
6
{
"Business"
;
break
;
}
7
{
"Server Standard"
;
break
;
}
8
{
"Server Datacenter (full installation)"
;
break
;
}
9
{
"Windows Small Business Server"
;
break
;
}
10
{
"Server Enterprise (full installation)"
;
break
;
}
11
{
"Starter"
;
break
;
}
12
{
"Server Datacenter (core installation)"
;
break
;
}
13
{
"Server Standard (core installation)"
;
break
;
}
14
{
"Server Enterprise (core installation)"
;
break
;
}
15
{
"Server Enterprise for Itanium-based Systems"
;
break
;
}
16
{
"Business N"
;
break
;
}
17
{
"Web Server (full installation)"
;
break
;
}
18
{
"HPC Edition"
;
break
;
}
19
{
"Windows Storage Server 2008 R2 Essentials"
;
break
;
}
20
{
"Storage Server Express"
;
break
;
}
21
{
"Storage Server Standard"
;
break
;
}
22
{
"Storage Server Workgroup"
;
break
;
}
23
{
"Storage Server Enterprise"
;
break
;
}
24
{
"Windows Server 2008 for Windows Essential Server Solutions"
;
break
;
}
25
{
"Small Business Server Premium"
;
break
;
}
26
{
"Home Premium N"
;
break
;
}
27
{
"Enterprise N"
;
break
;
}
28
{
"Ultimate N"
;
break
;
}
29
{
"Web Server (core installation)"
;
break
;
}
30
{
"Windows Essential Business Server Management Server"
;
break
;
}
31
{
"Windows Essential Business Server Security Server"
;
break
;
}
32
{
"Windows Essential Business Server Messaging Server"
;
break
;
}
33
{
"Server Foundation"
;
break
;
}
34
{
"Windows Home Server 2011"
;
break
;
}
35
{
"Windows Server 2008 without Hyper-V for Windows Essential Server"
;
break
;
}
36
{
"Server Standard without Hyper-V"
;
break
;
}
37
{
"Server Datacenter without Hyper-V (full installation)"
;
break
;
}
38
{
"Server Enterprise without Hyper-V (full installation)"
;
break
;
}
39
{
"Server Datacenter without Hyper-V (core installation)"
;
break
;
}
40
{
"Server Standard without Hyper-V (core installation)"
;
break
;
}
41
{
"Server Enterprise without Hyper-V (core installation)"
;
break
;
}
42
{
"Microsoft Hyper-V Server"
;
break
;
}
43
{
"Storage Server Express (core installation)"
;
break
;
}
44
{
"Storage Server Standard (core installation)"
;
break
;
}
45
{
"Storage Server Workgroup (core installation)"
;
break
;
}
46
{
"Storage Server Enterprise (core installation)"
;
break
;
}
46
{
"Storage Server Enterprise (core installation)"
;
break
;
}
47
{
"Starter N"
;
break
;
}
48
{
"Professional"
;
break
;
}
49
{
"Professional N"
;
break
;
}
50
{
"Windows Small Business Server 2011 Essentials"
;
break
;
}
51
{
"Server For SB Solutions"
;
break
;
}
52
{
"Server Solutions Premium"
;
break
;
}
53
{
"Server Solutions Premium (core installation)"
;
break
;
}
54
{
"Server For SB Solutions EM"
;
break
;
}
55
{
"Server For SB Solutions EM"
;
break
;
}
56
{
"Windows MultiPoint Server"
;
break
;
}
59
{
"Windows Essential Server Solution Management"
;
break
;
}
60
{
"Windows Essential Server Solution Additional"
;
break
;
}
61
{
"Windows Essential Server Solution Management SVC"
;
break
;
}
62
{
"Windows Essential Server Solution Additional SVC"
;
break
;
}
63
{
"Small Business Server Premium (core installation)"
;
break
;
}
64
{
"Server Hyper Core V"
;
break
;
}
72
{
"Server Enterprise (evaluation installation)"
;
break
;
}
76
{
"Windows MultiPoint Server Standard (full installation)"
;
break
;
}
77
{
"Windows MultiPoint Server Premium (full installation)"
;
break
;
}
79
{
"Server Standard (evaluation installation)"
;
break
;
}
80
{
"Server Datacenter (evaluation installation)"
;
break
;
}
84
{
"Enterprise N (evaluation installation)"
;
break
;
}
95
{
"Storage Server Workgroup (evaluation installation)"
;
break
;
}
96
{
"Storage Server Standard (evaluation installation)"
;
break
;
}
98
{
"Windows 8 N"
;
break
;
}
99
{
"Windows 8 China"
;
break
;
}
100
{
"Windows 8 Single Language"
;
break
;
}
101
{
"Windows 8"
;
break
;
}
103
{
"Professional with Media Center"
;
break
;
}
default
{
"UNKNOWN: "
+
$SKU
}
}
Aunque se utiliza como una forma de expresar declaraciones condicionales de gran tamaño de forma más limpia, una declaración switch
funciona de forma muy similar a una gran secuencia de declaraciones if
, en contraposición a una gran secuencia de declaraciones if
... elseif
... elseif
... else
. Dada la entrada que proporciones, PowerShell evalúa esa entrada con cada una de las comparaciones de la sentencia switch
. Si el resultado de la comparación es true
, PowerShell ejecuta el bloque de secuencia de comandos que le sigue. A menos que ese bloque de secuencia de comandos contenga una sentencia break
,PowerShell continúa evaluando las siguientes comparaciones.
Para más información sobre la sentencia switch
de PowerShell, consulta "Sentencias condicionales" o escribe Get-Help about_Switch
.
Ver también
4.4 Repetir operaciones con bucles
Solución
Utiliza una de las sentencias en bucle de PowerShell (for
, foreach
, while
, y do
) o el cmdlet ForEach-Object
de PowerShell para ejecutar un comando o bloque de script más de una vez. Para una descripción detallada de estas sentencias en bucle, consulta "Sentencias en bucle". Por ejemplo:
for
bucle-
for
(
$counter
=
1
;
$counter
-le
10
;
$counter
++)
{
"Loop number $counter"
}
foreach
bucle-
foreach
(
$file
in
dir
)
{
"File length: "
+
$file
.
Length
}
ForEach-Object
cmdlet-
Get-ChildItem
|
ForEach
-Object
{
"File length: "
+
$_
.
Length
}
while
bucle-
$response
=
""
while
(
$response
-ne
"QUIT"
)
{
$response
=
Read-Host
"Type something"
}
do..while
bucle-
$response
=
""
do
{
$response
=
Read-Host
"Type something"
}
while
(
$response
-ne
"QUIT"
)
do..until
bucle-
$response
=
""
do
{
$response
=
Read-Host
"Type something"
}
until
(
$response
-eq
"QUIT"
)
Debate
Aunque cualquiera de las sentencias de bucle puede escribirse para que sea funcionalmente equivalente a cualquiera de las otras, cada una se presta a ciertos problemas.
En sueles utilizar un bucle for
cuando necesitas realizar una operación un número exacto de veces. Como utilizarlo de esta forma es tan habitual, a menudo se denomina bucle contado for
.
Normalmente utilizas un bucle foreach
cuando tienes una colección de objetos y quieres visitar cada elemento de esa colección. Si aún no tienes toda esa colección en memoria (como en la colección dir
del ejemplo foreach
mostrado anteriormente), el cmdlet ForEach-Object
suele ser una alternativa más eficiente.
A diferencia del bucle foreach
, el cmdlet ForEach-Object
te permite procesar cada elemento de la colección a medida que PowerShell lo genera. Esta es una distinción importante; pedir a PowerShell que recoja toda la salida de un comando grande (como Get-Content
hugefile.txt
) en un bucle foreach
puede arrastrar fácilmente tu sistema.
Al igual que las funciones orientadas al canal, el cmdlet ForEach-Object
te permite definir comandos para ejecutar antes de que comience el bucle, durante el bucle y después de que éste finalice:
PS > "a","b","c" | ForEach-Object ` -Begin { "Starting"; $counter = 0 } ` -Process { "Processing $_"; $counter++ } ` -End { "Finishing: $counter" } Starting Processing a Processing b Processing c Finishing: 3
Consejo
Para invocar varias operaciones en tu bucle al mismo tiempo, utiliza el modificador -paralelo de ForEach-Object
. Para más información, consulta la Receta 4.5.
Los bucles while
y do..while
son similares, en el sentido de que continúan ejecutando el bucle mientras su condición se evalúe como true
. Un bucle while
comprueba esto antes de ejecutar su bloque de secuencia de comandos, mientras que un bucle do..while
comprueba la condición después de ejecutar su bloque de secuencia de comandos. Un bucle do..until
es exactamente igual que un bucle do..while
, salvo que sale cuando su condición devuelve $true
, en lugar de cuando su condición devuelve $false
.
Para una descripción detallada de estas sentencias en bucle, consulta "Sentencias en bucle" o escribe Get-Help about_For
, Get-Help about_Foreach
, Get-Help about_While
o Get-Help about_Do
.
4.5 Procesar en paralelo la acción que consume tiempo
Solución
Utiliza el modificador -parallel
del cmdlet ForEach-Object
:
PS > Measure-Command { 1..5 | ForEach-Object { Start-Sleep -Seconds 5 } } (...) TotalSeconds : 25.0247856 (...) PS > Measure-Command { 1..5 | ForEach-Object -parallel { Start-Sleep -Seconds 5 } } (...) TotalSeconds : 5.1354752 (...)
Debate
Hay ocasiones en PowerShell en las que puedes acelerar significativamente una operación de larga duración ejecutando partes de ella al mismo tiempo. Las oportunidades perfectas para ello son los escenarios en los que tu script pasa la mayor parte del tiempo esperando en recursos de red (como la descarga de archivos o páginas web) u operaciones lentas (como el reinicio de una serie de servicios lentos).
En estos escenarios, puedes utilizar el parámetro -parallel
de ForEach-Object
para realizar estas acciones al mismo tiempo. Bajo cuerda, PowerShell utiliza trabajos en segundo plano para ejecutar cada rama. Limita el número de ramas que se ejecutan al mismo tiempo a lo que especifiques en el parámetro -ThrottleLimit
, con un valor por defecto de 5
.
Nota
Si la razón por la que quieres varios comandos en paralelo es realizar alguna tarea rápidamente en un gran conjunto de máquinas, debes utilizar en su lugar Invoke-Command
. Para más información, consulta la Receta 29.5.
Como PowerShell ejecuta estas ramas como trabajos en segundo plano, tienes que utilizar la sintaxis $USING
para introducir variables externas en este trabajo en segundo plano (PowerShell introduce $_
por defecto) o proporcionar las variables en el parámetro -ArgumentList
. Por ejemplo
PS > $greeting = "World" PS > 1..5 | ForEach-Object -parallel { "Hello $greeting" } Hello Hello Hello Hello Hello PS > 1..5 | ForEach-Object -parallel { "Hello $USING:greeting" } Hello World Hello World Hello World Hello World Hello World
PowerShell ejecuta estos trabajos en segundo plano en tu proceso PowerShell principal, para que puedas actuar sobre la entrada como instancias vivas:
$processes
=
1
..
10
|
ForEach
-Object
{
Start-Process
notepad
-PassThru
}
$processes
|
ForEach
-Object
-parallel
{
$_
.
Kill
()
}
Si necesitas que las ramas de tu bucle paralelo se comuniquen de nuevo con tu shell principal, el enfoque recomendado es conseguirlo mediante la salida del bloque de script y luego hacer que tu shell principal procese los resultados. Es tentador hacer esto con objetos vivos, pero ten cuidado porque el camino es traicionero y difícil. Tomemos un ejemplo sencillo: ejecutar una operación paralela para incrementar un contador.
Al principio puede parecer que debes utilizar
$counter
=
0
1
..
10
|
ForEach
-Object
-parallel
{
$myCounter
=
$USING
:
counter
$myCounter
=
$myCounter
+
1
}
Sin embargo, cuando escribes $counter = $counter + 1
en PowerShell, PowerShell actualiza la variable $counter
en el ámbito actual. Si quieres cambiar un objeto desde un trabajo en segundo plano, tienes que hacerlo estableciendo una propiedad en un objeto activo en lugar de intentar sustituir el objeto. Afortunadamente, PowerShell tiene un tipo llamado [ref]
para este tipo de escenario:
$counter
=
[ref]
0
1
..
10
|
ForEach
-Object
-parallel
{
$myCounter
=
$USING
:
counter
$myCounter
.
Value
=
$myCounter
.
Value
+
1
}
Inicialmente, esto parece funcionar:
PS > $counter Value ----- 10
Ahora que estamos orgullosos de nosotros mismos, hagámoslo realmente en paralelo:
$counter
=
[ref]
0
1
..
10000
|
ForEach
-Object
-throttlelimit
100
-parallel
{
$myCounter
=
$USING
:
counter
$myCounter
.
Value
=
$myCounter
.
Value
+
1
}
PS > $counter Value ----- 9992
¡Uy! Como hemos hecho esto con un paralelismo masivo, $myCounter.Value
puede cambiar en cualquier momento durante las partes del pipeline en las que PowerShell se ejecuta $myCounter.Value = $myCounter.Value + 1
. Esto se llama una condición de carrera, y es común a cualquier lenguaje que permita que el código de varios bloques de código simultáneos se ejecute al mismo tiempo. Para librarnos de los extraños estados intermedios, tenemos que utilizar la clase Incremento entrelazado del .Net Framework:
$counter
=
[ref]
0
1
..
10000
|
ForEach
-Object
-throttlelimit
100
-parallel
{
$myCounter
=
$USING
:
counter
$null
=
[Threading.Interlocked]
::
Increment
(
$myCounter
)
}
Lo que nos da correctamente:
PS > $counter Value ----- 10000
Estos problemas son espinosos, y muerden con regularidad incluso a los programadores profesionales. La mejor práctica para tratar este tipo de problemas es evitar la zona por completo, no procesando ni operando sobre estado compartido.
4.6 Añadir una Pausa o Retraso
Solución
Para hacer una pausa en hasta que el usuario pulse la tecla Intro, utiliza el comando pause
:
PS > pause Press Enter to continue...:
Para pausar hasta que el usuario pulse cualquier tecla, utiliza el método ReadKey()
en el objeto $host
:
PS > $host.UI.RawUI.ReadKey()
Para poner en pausa un script durante un tiempo determinado, utiliza el cmdlet Start-Sleep
:
PS > Start-Sleep 5 PS > Start-Sleep -Milliseconds 300
Debate
Cuando quieras pausar tu script hasta que el usuario pulse una tecla o durante un tiempo determinado, pause
y Start-Sleep
son los dos cmdlets que probablemente utilizarás.
Nota
Si quieres recuperar la entrada del usuario en lugar de hacer una pausa, el cmdlet Read-Host
te permite leer la entrada del usuario. Para más información, consulta la Receta 13.1.
En otras situaciones, a veces querrás escribir un bucle en tu script que se ejecute a una velocidad constante, como una vez por minuto o 30 veces por segundo. Esto suele ser una tarea difícil, ya que los comandos del bucle pueden ocupar una cantidad de tiempo considerable, o incluso incoherente.
En el pasado, muchos juegos de ordenador sufrían por resolver este problema de forma incorrecta. Para controlar la velocidad de su juego, los desarrolladores de juegos añadían comandos para ralentizarlo. Por ejemplo, después de muchos ajustes y jugueteos, los desarrolladores pueden darse cuenta de que el juego funciona correctamente en una máquina normal si hacen que el ordenador cuente hasta 1 millón cada vez que actualiza la pantalla. Por desgracia, la velocidad de estos comandos (como contar) depende en gran medida de la velocidad del ordenador. Como un ordenador rápido puede contar hasta 1 millón mucho más deprisa que un ordenador lento, ¡el juego acaba ejecutándose mucho más deprisa (a menudo hasta el punto de resultar incomprensible) en ordenadores más rápidos!
Para hacer que tu bucle se ejecute a una velocidad regular, puedes medir cuánto tardan en completarse los comandos de un bucle, y luego retrasarlo el tiempo que quede, como se muestra en el Ejemplo 4-1.
Ejemplo 4-1. Ejecutar un bucle a velocidad constante
$loopDelayMilliseconds
=
650
while
(
$true
)
{
$startTime
=
Get-Date
## Do commands here
"Executing"
$endTime
=
Get-Date
$loopLength
=
(
$endTime
-
$startTime
).
TotalMilliseconds
$timeRemaining
=
$loopDelayMilliseconds
-
$loopLength
if
(
$timeRemaining
-gt
0
)
{
Start-Sleep
-Milliseconds
$timeRemaining
}
}
Para más información sobre el cmdlet Start-Sleep
, escribe Get-Help Start-Sleep
.
Get Libro de cocina PowerShell, 4ª edición now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.