Colección práctica de comandos de PowerShell ── Amplíe las pequeñas funciones que usa a diario

· Actualizado el: · · PowerShell, Windows, Línea de comandos, Automatización, Mejora de la eficiencia operativa, Aprovechamiento de activos existentes

1. Lo primero que debe tener en cuenta

Una vez que domine los fundamentos de PowerShell, el siguiente paso es ir ampliando las «pequeñas funciones que se usan con frecuencia», lo cual facilita mucho el trabajo diario.

Aquí, «pequeñas funciones» no se refiere a los alias abreviados. En este artículo no se usan formas abreviadas como ls o cat, sino los nombres de comando oficiales, como Get-ChildItem, Get-Content o Select-String.

Sobre esa base, el objetivo es poder realizar tareas como las siguientes con un comando de una sola línea o de unas pocas líneas.

Contar el número de elementos
Calcular el tamaño total
Eliminar duplicados
Agregar por tipo
Extraer solo los valores necesarios
Comparar dos resultados
Ver las líneas anteriores y posteriores de un registro
Enviar al portapapeles
Guardar el resultado de ejecución y mostrarlo en pantalla al mismo tiempo
Comprobar variables de entorno y la red

PowerShell resulta útil incluso sin escribir scripts largos. El primer paso es ampliar las «piezas de uso frecuente» para poder combinarlas poco a poco en el trabajo diario.

Más que memorizar los comandos, lo importante es poder recordar «en esta situación puedo usar esta pieza».

El código que aparece en este artículo se publica en GitHub como un conjunto completo de ejemplos ejecutables (scripts de recetas y pruebas Pester), organizado por temas siguiendo la estructura de capítulos.

powershell-practical-command-recipes - komurasoft-blog-samples (GitHub)

Diferencias con el artículo anterior

Este artículo es la continuación de Fundamentos de los comandos de PowerShell ── Las operaciones que debe aprender primero y su uso seguro. Los roles se dividen de la siguiente manera.

  Fundamentos de los comandos de PowerShell Este artículo
Objetivo Aprender a manejar PowerShell Aprender a contar, resumir, comparar y conservar los resultados obtenidos
Enfoque central Sintaxis, canalización (pipeline) y cómo encontrar comandos Piezas para agregación, comparación, extracción y salida
CSV / JSON Fundamentos de lectura y escritura El lado que filtra y agrega los resultados leídos según condiciones
Procesos / servicios / registros de eventos Fundamentos para obtener listados El lado que cuenta los listados obtenidos por tipo y calcula diferencias
Comandos de modificación El propio orden para ejecutarlos con seguridad Los comandos de investigación y evidencia que se incorporan a ese orden

Es decir, el artículo anterior llega hasta el punto de «poder extraer valores», mientras que este artículo trata sobre «qué hacer con los valores extraídos».

Los fundamentos de los comandos de obtención como Get-ChildItem, Get-Content, Import-Csv o Get-Service, junto con la política de ejecución, la forma de escribir archivos .ps1 y el manejo de errores, se explican en el artículo anterior. Este artículo avanza dando esos temas por conocidos. Hay algunos puntos que aparecen en ambos artículos, como usar los comandos Format al final o Export-Csv -Encoding UTF8, pero aquí se abordan desde el ángulo de «cómo llevarlos a la agregación o a la comparación».

2. El enfoque de este artículo

Las premisas son las siguientes tres.

  1. Escribir los comandos con su nombre oficial
  2. Centrarse en los comandos de lectura
  3. Considerar siempre los comandos de modificación junto con la verificación del objetivo y -WhatIf

Por ejemplo, es más seguro dominar primero el siguiente flujo que aprender directamente el comando para eliminar archivos.

Ver el objetivo
  → Filtrar por condición
  → Contar el número de elementos
  → Guardarlo en CSV si es necesario
  → Confirmar el plan de cambio
  → Ejecutar

En este artículo se da prioridad a la investigación, la agregación, la comparación y la salida de datos, más que a operaciones fuertes como eliminar o detener.

3. Mapa de los comandos más habituales

Estos son los principales comandos que se usan en este artículo. En el extremo derecho se indica el capítulo donde se tratan en detalle.

Qué se quiere hacer Comando Capítulo
Averiguar el número de elementos o el total Measure-Object 4, 5
Extraer solo los valores necesarios Select-Object -ExpandProperty 6
Eliminar duplicados Sort-Object -Unique 7
Agregar por tipo Group-Object 8
Mostrar solo las columnas necesarias o crear columnas calculadas Select-Object 9
Ordenar Sort-Object 10
Buscar cadenas de texto Select-String 12
Comparar dos resultados Compare-Object 14
Calcular un valor hash Get-FileHash 15
Usar el portapapeles Set-Clipboard / Get-Clipboard 16
Mostrar en pantalla y guardar en archivo a la vez Tee-Object 17
Dejar constancia del trabajo en un registro Start-Transcript 18
Comprobar la conectividad de red Test-Connection / Test-NetConnection 26
Medir el tiempo de procesamiento Measure-Command 28
Ver el detalle de un error Get-Error 31
Procesar cada elemento ForEach-Object Según el capítulo

No hace falta memorizarlos todos de una vez. Se recomienda aprenderlos junto con su propósito, como «para contar, Measure-Object», «para agrupar, Group-Object» o «para comparar, Compare-Object».

Mapa de capítulos por objetivo

Del capítulo 4 al 36, el contenido se divide en los siguientes bloques. Lea la parte que le interese.

Categoría Capítulos Contenido
Agregación y formato 4-11 Número de elementos, total, máximo y promedio, extracción de valores, eliminación de duplicados, agregación por tipo, columnas calculadas, ordenación, y el papel de los comandos Format
Investigación de texto y registros 12-14 Búsqueda de cadenas y líneas de contexto, reemplazo, comparación de dos listas
Contenido de archivos y datos 15, 19, 20 Verificación de valores hash, filtrado de CSV, valores de configuración en JSON
Salida y evidencia 16-18 Enviar al portapapeles, salida simultánea a pantalla y archivo, registro de trabajo
Investigación del sistema 21-25, 31 Variables de entorno, perfil, procesos, servicios, registros de eventos, detalle de errores
Red 26, 27 Verificación de conectividad, respuesta web
Forma de ejecución 28-30 Medición del tiempo de ejecución, ejecución en segundo plano, historial de comandos
Repaso de sintaxis 32 Operadores de comparación
Recetas listas para usar 33, 34 11 recetas prácticas y precauciones al combinarlas con comandos de modificación
Tabla de referencia rápida 35 Chuleta para recordar comandos a partir del objetivo

Si ya sabe qué quiere averiguar pero no recuerda qué comando usar, el camino más rápido es empezar por la tabla de referencia rápida del capítulo 35.

4. Contar el número de elementos ── Measure-Object

Lo primero que se usa con frecuencia es contar el número de elementos.

Cuenta el número de archivos en la carpeta actual.

Get-ChildItem . -File | Measure-Object

En caso de contar incluyendo las subcarpetas.

Get-ChildItem . -File -Recurse | Measure-Object

El Count del resultado de Measure-Object es el número de elementos.

Si desea ver el tamaño total de los archivos, agregue la propiedad Length.

Get-ChildItem . -File -Recurse |
  Measure-Object -Property Length -Sum

Sin embargo, así el resultado queda en bytes, algo difícil de leer para una persona, así que lo convertimos a unidades de GB.

$size = Get-ChildItem . -File -Recurse |
  Measure-Object -Property Length -Sum

[math]::Round($size.Sum / 1GB, 2)

Esto resulta útil cuando quiere hacerse una idea aproximada del tamaño total de una carpeta.

5. También se pueden averiguar el máximo y el promedio

Measure-Object no solo calcula el total, también puede obtener el valor máximo y el promedio.

Get-ChildItem . -File |
  Measure-Object -Property Length -Sum -Average -Maximum -Minimum

Se puede usar para ver la dispersión de los tamaños de archivo.

También es posible sumar el tiempo de CPU acumulado de los procesos. La propiedad CPU de Get-Process no es un porcentaje de uso, sino los segundos de tiempo de CPU consumidos desde que se inició el proceso.

Get-Process |
  Measure-Object -Property CPU -Sum

Sin embargo, como este valor es acumulado y no un porcentaje instantáneo de uso de CPU, varía según el momento de ejecución y el tiempo que lleve funcionando el proceso.

Para fines de investigación resulta suficiente, pero si desea una supervisión rigurosa, necesitará herramientas de monitoreo especializadas y un diseño de registros adecuado.

6. Extraer solo el valor ── Select-Object -ExpandProperty

Select-Object se usa con frecuencia para seleccionar columnas.

Get-Process |
  Select-Object Name, Id, CPU

Esto genera «un objeto con las columnas Name, Id y CPU».

Por otro lado, cuando quiere extraer solo el valor, use -ExpandProperty.

Get-Process -Name notepad -ErrorAction SilentlyContinue |
  Select-Object -ExpandProperty Id

Lo mismo ocurre cuando se extrae solo el nombre del archivo.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Name

Cuando quiere pasar el resultado de un comando a otro comando o a un archivo de texto, -ExpandProperty resulta muy práctico.

Por ejemplo, guarde solo la lista de nombres de archivo.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\file-names.txt -Encoding UTF8

Select-Object Name y Select-Object -ExpandProperty Name son parecidos, pero el resultado tiene una forma diferente.

Select-Object Name
  → Una tabla con una columna llamada Name

Select-Object -ExpandProperty Name
  → El valor de Name en sí mismo

Si quiere generar un CSV, es mejor conservarlo como columna; si quiere pasarlo a otro procesamiento de cadenas, es más manejable tener solo el valor.

7. Eliminar duplicados ── Sort-Object -Unique

Caso en que desea obtener un listado con solo las extensiones de archivo.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Extension |
  Sort-Object -Unique

Al ejecutarlo, se muestran solo las extensiones sin duplicar, como .txt, .log o .csv.

También puede ver únicamente los tipos de nombres de proceso.

Get-Process |
  Select-Object -ExpandProperty ProcessName |
  Sort-Object -Unique

Ejemplo en el que se extrae solo el listado de nombres de departamento a partir de un CSV de usuarios.

Import-Csv .\users.csv |
  Select-Object -ExpandProperty Department |
  Sort-Object -Unique

Cuando «el listado tiene muchos valores repetidos y es difícil de leer», conviene recordar primero Sort-Object -Unique.

8. Agregar por tipo ── Group-Object

Cuando no basta con eliminar duplicados y quiere ver «cuántos elementos hay de cada tipo», use Group-Object.

Cuenta el número de archivos por extensión.

Get-ChildItem . -File |
  Group-Object -Property Extension -NoElement |
  Sort-Object -Property Count -Descending

La salida tiene esta forma. El número de elementos y las extensiones varían según el contenido de la carpeta, pero el orden de las columnas es el mismo.

Count Name
----- ----
   42 .log
   18 .csv
    7 .txt
    3

La fila donde Name está vacío corresponde a archivos sin extensión.

Si quita -NoElement, se añade una columna llamada Group que muestra los elementos que forman parte de ese grupo.

Count Name  Group
----- ----  -----
   42 .log  {app-20260601.log, app-20260602.log, app-20260603.log...}
   18 .csv  {export-01.csv, export-02.csv, export-03.csv...}

Cuando solo quiere ver el número de elementos, la columna Group satura la pantalla, así que se añade -NoElement. Por el contrario, cuando quiere comprobar qué contiene ese grupo, no se añade.

Cuenta por estado de servicio.

Get-Service |
  Group-Object -Property Status -NoElement

Cuenta por nivel del registro de eventos.

Get-WinEvent -LogName System -MaxEvents 500 |
  Group-Object -Property LevelDisplayName -NoElement

Group-Object resulta adecuado para hacerse una idea general al comienzo de una investigación.

Qué extensión es la más frecuente
Qué estado de servicio es el más frecuente
Qué nivel de error es el más frecuente
Qué departamento tiene más datos

Se usa cuando quiere ver primero la distribución antes de examinar el contenido en detalle.

9. Crear las columnas necesarias ── Añadir columnas calculadas

El tamaño de archivo se obtiene con Length, pero la unidad es el byte. Ver siempre el valor en bytes resulta incómodo, así que conviene crear una columna convertida a MB o KB.

Get-ChildItem . -File |
  Select-Object Name, @{Name="SizeKB"; Expression={ [math]::Round($_.Length / 1KB, 1) }}, LastWriteTime

Ejemplo en el que se ven los archivos, incluidas las subcarpetas, ordenados de mayor a menor tamaño.

Get-ChildItem . -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 20 FullName, @{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }}, LastWriteTime

@{Name="..."; Expression={ ... }} es la sintaxis para crear una columna calculada. Al principio parece un poco larga, pero se usa con frecuencia en el trabajo práctico.

Por ejemplo, puede mostrar el uso de memoria de los procesos en MB.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

Al incluirlo en un informe, una columna como SizeMB resulta más legible que el Length original.

10. Ver por orden de más reciente, más antiguo o mayor tamaño

En PowerShell, la ordenación se realiza con Sort-Object.

Ver los archivos actualizados recientemente.

Get-ChildItem . -File |
  Sort-Object -Property LastWriteTime -Descending |
  Select-Object -First 10 Name, LastWriteTime

Ver los archivos más antiguos.

Get-ChildItem . -File |
  Sort-Object -Property LastWriteTime |
  Select-Object -First 10 Name, LastWriteTime

Ver los archivos más grandes.

Get-ChildItem . -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 10 FullName, Length

Estas tres formas se usan con frecuencia.

Más reciente primero → LastWriteTime -Descending
Más antiguo primero  → LastWriteTime
Mayor tamaño primero → Length -Descending

Es una combinación que se usa mucho en la investigación de registros, la limpieza de archivos innecesarios y el estudio del espacio en disco.

11. Use los comandos Format solo al final, para la visualización en pantalla

Cuando quiere que el resultado sea más fácil de leer en pantalla, use Format-Table o Format-List.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Format-Table -AutoSize

Para ver el detalle de un solo elemento, Format-List resulta muy práctico.

Get-Process -Id $PID |
  Format-List *

Sin embargo, Format-Table y Format-List son «para visualización».

Es más seguro no usarlos antes de exportar a CSV o antes de procesar el resultado con el siguiente comando.

# Evitar esto
Get-Process |
  Format-Table Name, Id |
  Export-Csv .\process.csv -NoTypeInformation

Si va a exportar a CSV, seleccione las columnas con Select-Object.

# Correcto
Get-Process |
  Select-Object Name, Id |
  Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8

Si tiene dudas, piense de la siguiente manera.

Solo para ver en pantalla → Format-Table / Format-List
Para usar después         → Select-Object

12. Haga la búsqueda en registros un poco más práctica ── Select-String

Para buscar cadenas de texto, use Select-String.

Select-String -Path .\logs\*.log -Pattern "ERROR"

También se pueden especificar varios patrones.

Select-String -Path .\logs\*.log -Pattern "ERROR", "WARN", "FATAL"

Si también quiere ver las líneas anteriores y posteriores, use -Context.

Select-String -Path .\logs\*.log -Pattern "ERROR" -Context 2

Esto muestra también las 2 líneas anteriores y posteriores a la línea encontrada, lo que resulta útil cuando quiere revisar el contexto de un error.

Si quiere buscar como una cadena literal simple, use -SimpleMatch.

Select-String -Path .\logs\*.log -Pattern "[ERROR]" -SimpleMatch

El parámetro -Pattern de Select-String normalmente se interpreta como una expresión regular. Si quiere buscar símbolos como [ o . de forma literal, añadir -SimpleMatch lo hace más claro.

Caso en que desea distinguir entre mayúsculas y minúsculas.

Select-String -Path .\logs\*.log -Pattern "Error" -CaseSensitive

También puede guardar el resultado de la búsqueda en un CSV.

Select-String -Path .\logs\*.log -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8

13. Reemplazar cadenas de texto

Para reemplazar una parte del texto, use -replace.

"server01.example.com" -replace "\.example\.com$", ""

Al reemplazar el contenido de un archivo, es más seguro no sobrescribir directamente el archivo original. Primero, envíe el resultado a un archivo distinto.

(Get-Content .\appsettings.json -Raw) -replace "localhost", "db01" |
  Set-Content .\appsettings.preview.json -Encoding UTF8

Después de verificarlo, aplíquelo al archivo original si es necesario.

En archivos de configuración o reemplazos masivos, si hay demasiados elementos afectados se producen incidentes. Es más seguro confirmar primero los objetivos con Select-String antes de reemplazar.

Select-String -Path .\appsettings.json -Pattern "localhost" -SimpleMatch

14. Comparar dos resultados ── Compare-Object

Compare-Object es un comando para ver las diferencias entre dos listas.

Cuándo usarlo: se usa para confirmar que la configuración no ha cambiado antes y después de un trabajo, para cotejar la configuración o el listado de software instalado entre dos equipos, o para comparar la configuración de servicios entre producción y verificación. Resulta útil para confirmar que «algo debería seguir igual».

Por ejemplo, compare el listado de nombres de archivo antes y después de un cambio.

Compare-Object `
  -ReferenceObject (Get-Content .\before.txt) `
  -DifferenceObject (Get-Content .\after.txt)

Si before.txt contiene a.log, b.log y c.log, y after.txt contiene b.log, c.log y d.log, la salida sería la siguiente.

InputObject SideIndicator
----------- -------------
d.log       =>
a.log       <=

b.log y c.log, que están en ambos, no se muestran de forma predeterminada. Solo se muestran las diferencias.

El significado de SideIndicator es el siguiente.

Símbolo Significado
<= Solo está en el lado izquierdo, es decir, en ReferenceObject
=> Solo está en el lado derecho, es decir, en DifferenceObject
== Está en ambos. Se muestra al añadir -IncludeEqual

Resulta fácil recordar el sentido de las flechas si las lee como «hacia qué lado se inclina»: ReferenceObject (izquierda) o DifferenceObject (derecha). En el ejemplo anterior, a.log solo está en el lado izquierdo (antes del cambio), por lo que es un archivo eliminado; d.log solo está en el lado derecho (después del cambio), por lo que es un archivo añadido.

Ejemplo en el que se guarda el listado de nombres de archivo de una carpeta y se compara.

Get-ChildItem .\before -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\before-list.txt -Encoding UTF8

Get-ChildItem .\after -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\after-list.txt -Encoding UTF8

Compare-Object `
  -ReferenceObject (Get-Content .\before-list.txt) `
  -DifferenceObject (Get-Content .\after-list.txt)

También se puede ver el cambio en un listado de servicios.

Get-Service |
  Select-Object Name, Status |
  Export-Csv .\services-before.csv -NoTypeInformation -Encoding UTF8

Después del cambio, se genera de nuevo.

Get-Service |
  Select-Object Name, Status |
  Export-Csv .\services-after.csv -NoTypeInformation -Encoding UTF8

Se compara.

Compare-Object `
  -ReferenceObject (Import-Csv .\services-before.csv) `
  -DifferenceObject (Import-Csv .\services-after.csv) `
  -Property Name, Status

Conservar las diferencias antes y después del trabajo facilita la investigación y la elaboración de informes.

15. Verificar el valor hash de un archivo ── Get-FileHash

Cuando quiere comprobar si un archivo descargado o distribuido es el mismo, use el valor hash.

Get-FileHash .\installer.exe -Algorithm SHA256

Caso en que desea verificar en bloque los archivos de una carpeta.

Get-ChildItem .\downloads -File |
  ForEach-Object { Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256 }

También se puede guardar en un CSV.

Get-ChildItem .\downloads -File |
  ForEach-Object { Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256 } |
  Select-Object Path, Hash |
  Export-Csv .\hashes.csv -NoTypeInformation -Encoding UTF8

Aunque el nombre de archivo parezca el mismo, el contenido puede ser diferente. En material de distribución, copias de seguridad o trabajos de migración, conservar el valor hash facilita la verificación.

16. Enviar al portapapeles ── Set-Clipboard

Cuándo usarlo: se usa cuando quiere pegar el resultado de una investigación directamente en la respuesta a una consulta o en un informe de incidencia, o pegarlo en Excel para convertirlo en una tabla. Se ahorra por completo el proceso de crear un archivo, abrirlo, seleccionar y copiar.

Cuando quiere pegar el resultado de un comando en un correo o en un chat, resulta práctico enviarlo al portapapeles.

Get-Service |
  Select-Object Name, Status |
  ConvertTo-Csv -NoTypeInformation |
  Set-Clipboard

Caso en que desea ver el contenido del portapapeles.

Get-Clipboard

Si quiere delimitarlo con tabulaciones para pegarlo en Excel, cambie el carácter delimitador de ConvertTo-Csv a una tabulación.

Get-Process |
  Select-Object Name, Id, CPU |
  ConvertTo-Csv -NoTypeInformation -Delimiter "`t" |
  Set-Clipboard

Si solo quiere compartir el resultado de forma temporal, es más cómodo que crear un archivo cada vez. Sin embargo, si desea dejar constancia como evidencia, guárdelo en un archivo con Export-Csv.

17. Mostrar en pantalla y guardar en archivo a la vez ── Tee-Object

Cuando quiere ver el resultado en pantalla y al mismo tiempo guardarlo en un archivo, use Tee-Object.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Tee-Object -FilePath .\top-process.txt

Tee-Object envía el resultado de la canalización en dos direcciones.

Mostrarlo en pantalla
Guardarlo también en un archivo

Resulta adecuado durante una investigación para «ver y registrar al mismo tiempo». Sin embargo, si más adelante quiere abrirlo en Excel, Export-Csv es más fácil de manejar.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Export-Csv .\top-process.csv -NoTypeInformation -Encoding UTF8

Resulta claro pensarlo así: Tee-Object para la pantalla y Export-Csv para conservarlo como datos tabulares.

18. Dejar constancia del trabajo en un registro ── Start-Transcript

Cuándo usarlo: se usa al trabajar en un entorno de producción, en situaciones donde después necesitará informar «qué se ejecutó y en qué orden». Es algo que se ejecuta una vez antes de empezar, como evidencia de la respuesta a incidencias o de las tareas de mantenimiento.

Cuando quiere registrar una serie de operaciones, use Start-Transcript.

Start-Transcript -Path .\work-log.txt

A partir de aquí se registran los comandos ejecutados y la salida en pantalla.

Para finalizar.

Stop-Transcript

En el trabajo de investigación, más adelante suele necesitar confirmar lo siguiente.

Qué comando se ejecutó
En qué carpeta se trabajó
Qué resultado se obtuvo
Si se produjo algún error

Usar Start-Transcript sirve como seguro para cuando olvida tomar notas del trabajo. Sin embargo, tenga cuidado al usarlo en tareas donde en pantalla aparezca información que no debe registrarse, como contraseñas o tokens.

19. Leer un CSV y filtrarlo por condición

En los datos empresariales, el formato CSV aparece con frecuencia.

Por ejemplo, suponga que existe el siguiente archivo users.csv.

Name,Department,Enabled
Suzuki,Sales,true
Tanaka,Accounting,false
Sato,Sales,true

Se carga.

Import-Csv .\users.csv

Ver solo las personas cuyo departamento es Sales.

Import-Csv .\users.csv |
  Where-Object { $_.Department -eq "Sales" }

Exportar solo los usuarios habilitados a otro CSV.

Import-Csv .\users.csv |
  Where-Object { $_.Enabled -eq "true" } |
  Export-Csv .\enabled-users.csv -NoTypeInformation -Encoding UTF8

Como los valores de un CSV suelen tratarse como cadenas de texto, al comparar true / false o valores numéricos, considere la conversión de tipo cuando sea necesario.

Por ejemplo, caso en que desea ver solo las filas con una puntuación de 80 o más.

Import-Csv .\scores.csv |
  Where-Object { [int]$_.Score -ge 80 }

20. Ver valores de configuración en JSON

JSON se usa con frecuencia en archivos de configuración y en API web.

$config = Get-Content .\settings.json -Raw | ConvertFrom-Json
$config

También puede ver solo un valor específico.

$config.Database.Host

Ejemplo en el que se cambia un valor y se guarda en otro archivo.

$config.Database.Host = "db01"
$config |
  ConvertTo-Json -Depth 10 |
  Set-Content .\settings.updated.json -Encoding UTF8

Al trabajar con JSON, se suele usar Get-Content -Raw. Al añadir -Raw, el archivo completo se lee como una única cadena de texto, lo que resulta más claro cuando se maneja JSON de varias líneas.

21. Ver variables de entorno

Las variables de entorno se usan con frecuencia para la configuración de aplicaciones y la verificación de rutas.

Ver el listado.

Get-ChildItem Env:

Ver el nombre del usuario actual.

$env:USERNAME

Ver la carpeta temporal.

$env:TEMP

Dividir la variable PATH para verla con más claridad.

$env:PATH -split ";"

Establecer una variable de entorno solo para la sesión actual de PowerShell.

$env:APP_MODE = "Development"

Esta configuración solo es válida dentro de la sesión de PowerShell que tiene abierta en este momento.

Si desea guardarla como variable de entorno del usuario, hágalo de la siguiente manera.

[Environment]::SetEnvironmentVariable("APP_MODE", "Development", "User")

Como esta es una operación que modifica el entorno, en un equipo corporativo o en un servidor de producción, verifique primero el alcance del impacto antes de llevarla a cabo.

22. Verificar el perfil

PowerShell tiene un perfil que se carga al iniciar.

Verificar la ubicación.

$PROFILE

Verificar si existe.

Test-Path $PROFILE

Caso en que desea crearlo.

New-Item -ItemType File -Path $PROFILE -Force

Abrir con el Bloc de notas.

notepad $PROFILE

Resulta práctico escribir en el perfil la configuración o las funciones que usa con frecuencia. Sin embargo, si escribe procesos demasiado complejos, el inicio de PowerShell se vuelve más lento y resulta más difícil reproducirlo en otro entorno, así que al principio se recomienda limitarse a rutas de uso frecuente y configuraciones de visualización.

23. Ver procesos

En la investigación de procesos, lo habitual es empezar viendo los que tienen mayor uso de memoria.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

Filtrar por un nombre específico.

Get-Process -Name notepad -ErrorAction SilentlyContinue

Para detener un proceso, no lo ejecute directamente: verifíquelo primero con -WhatIf.

Stop-Process -Name notepad -WhatIf

Si no hay problemas, ejecútelo.

Stop-Process -Name notepad

En un entorno de producción, detener un proceso puede tener impacto en la operación del negocio. Antes de detenerlo, verifique el objetivo, los usuarios afectados y el método de recuperación.

24. Ver servicios

Ver el listado de servicios.

Get-Service

Caso en que desea ver solo los servicios detenidos.

Get-Service |
  Where-Object { $_.Status -eq "Stopped" }

Buscar servicios configurados como inicio automático pero que están detenidos.

Get-Service |
  Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
  Select-Object Name, DisplayName, Status, StartType

También al reiniciar un servicio, primero verifique el objetivo.

Get-Service -Name "Spooler"

Hacer un ensayo.

Restart-Service -Name "Spooler" -WhatIf

Como las operaciones sobre servicios tienen un impacto considerable, verifique la ventana de mantenimiento y el procedimiento de recuperación antes de ejecutarlas.

25. Ver el registro de eventos

En la investigación de Windows, es habitual tener que revisar el registro de eventos.

Ver los 100 eventos más recientes del registro del sistema.

Get-WinEvent -LogName System -MaxEvents 100 |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

Filtrar solo por errores y advertencias.

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

Ver solo los errores de las últimas 24 horas.

$start = (Get-Date).AddHours(-24)

Get-WinEvent -FilterHashtable @{ LogName = "System"; StartTime = $start } |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message

Caso en que desea guardar el resultado de la investigación en un CSV.

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message |
  Export-Csv .\system-events.csv -NoTypeInformation -Encoding UTF8

Como el registro de eventos tiende a tener muchos elementos, es importante acotar el rango con -MaxEvents o especificando un período.

26. Comprobar la red

Para verificar la conectividad, use Test-Connection.

Test-Connection example.com -Count 4

Para verificar la conectividad de un puerto TCP en Windows, Test-NetConnection resulta muy práctico.

Test-NetConnection example.com -Port 443

Caso en que desea verificar la resolución DNS.

Resolve-DnsName example.com

En la investigación de red, se procede a diagnosticar por partes de la siguiente manera.

Si se resuelve el nombre
Si llega a la IP
Si el puerto deseado está abierto
Si no hay influencia de un proxy o un firewall

En lugar de intentar determinarlo todo únicamente con PowerShell, resulta práctico usarlo como punto de partida para el diagnóstico por partes.

27. Ver resultados de la web

Para obtener una página web, use Invoke-WebRequest.

Invoke-WebRequest https://example.com |
  Select-Object StatusCode, StatusDescription

Para trabajar con el resultado de una API JSON, Invoke-RestMethod resulta muy práctico.

Invoke-RestMethod https://api.github.com/repos/PowerShell/PowerShell |
  Select-Object full_name, stargazers_count, forks_count

El resultado de una API a menudo puede tratarse directamente como un objeto de PowerShell, lo que facilita combinarlo con Select-Object o Where-Object.

También al investigar una API interna, empiece por operaciones de lectura con GET.

Cuando maneje credenciales o tokens, tenga cuidado con lo que se muestra en pantalla o se registra en el transcript.

28. Medir el tiempo de ejecución ── Measure-Command

Cuándo usarlo: se usa para decidir si «este proceso puede incluirse en un trabajo por lotes nocturno», o para comparar si un cambio en la forma de escribir el código lo hizo más rápido. Permite decidir con datos numéricos en lugar de con impresiones subjetivas.

Cuando quiere saber cuánto tiempo tarda un proceso, use Measure-Command.

Measure-Command {
  Get-ChildItem C:\Windows -File -Recurse -ErrorAction SilentlyContinue |
    Measure-Object
}

El resultado incluye TotalSeconds y TotalMilliseconds.

$result = Measure-Command {
  Get-ChildItem . -File -Recurse | Measure-Object
}

$result.TotalSeconds

Cuando quiere hacer más rápido un script, es importante medir el tiempo en lugar de guiarse por impresiones subjetivas. Sin embargo, el resultado varía según el número de archivos, el estado del disco y el estado de la red, así que no lo decida con un solo resultado: compruébelo varias veces.

29. Ejecutar en segundo plano un proceso que tarda ── Start-Job

Cuándo usarlo: se usa cuando quiere lanzar un proceso que tarda varios minutos, como un recorrido completo de una carpeta grande o un cálculo de hash, y mientras tanto continuar con otra investigación. Por el contrario, convertir en un job un proceso que termina en unos segundos añade más esfuerzo de inicio del que ahorra.

Cuando quiere ejecutar como un job independiente una investigación que tarda tiempo, use Start-Job.

$job = Start-Job -ScriptBlock {
  Get-ChildItem C:\Windows -File -Recurse -ErrorAction SilentlyContinue |
    Measure-Object
}

Ver el estado del job.

Get-Job

Recibir el resultado.

Receive-Job $job

Eliminar un job que ya no es necesario.

Remove-Job $job

Start-Job es práctico, pero no hace falta usarlo en exceso desde el principio. Resulta más claro ejecutar primero de forma normal y convertir en job solo los procesos que realmente tardan.

30. Usar el historial de comandos

Cuándo usarlo: se usa cuando, tras armar un comando mediante prueba y error, ya funciona correctamente y quiere copiarlo a un procedimiento documentado o a un script.

Para ver los comandos ejecutados anteriormente, use Get-History.

Get-History

Mostrar de forma más clara solo las líneas de comando.

Get-History |
  Select-Object Id, CommandLine

Volver a ejecutar una entrada específica del historial.

Invoke-History 12

El historial es práctico, pero también permite volver a ejecutar comandos peligrosos. Al volver a ejecutar desde el historial comandos de modificación como Remove-Item o Stop-Process, verifique el contenido antes de ejecutarlos.

31. Ver el detalle de un error ── Get-Error

En PowerShell 7 puede usar Get-Error para ver en detalle el error más reciente.

Get-Error

Caso en que desea ver solo el mensaje del error más reciente.

$Error[0].Exception.Message

Cuando se produce un error, no se limite a mirar el texto en rojo de la pantalla: verifique también los siguientes puntos.

Con qué comando falló
En qué ruta u objeto falló
Si es un problema de permisos
Si el archivo no existe
Si es un problema de red o de bloqueo

Si desea dejar constancia del resultado de la investigación, combínelo con Start-Transcript o Export-Csv.

32. Operadores de comparación más habituales

En Where-Object se usan con frecuencia los operadores de comparación.

Operador Significado Ejemplo
-eq Igual a $_.Status -eq "Running"
-ne Distinto de $_.Status -ne "Running"
-gt Mayor que $_.Length -gt 10MB
-ge Mayor o igual que $_.Length -ge 10MB
-lt Menor que $_.Length -lt 10MB
-le Menor o igual que $_.Length -le 10MB
-like Coincidencia con comodines $_.Name -like "*.log"
-match Coincidencia con expresión regular $_.Name -match "^app"
-in El valor está incluido en la lista $_.Status -in @("Running", "Paused")
-contains La lista contiene el valor @("a", "b") -contains "a"

Ejemplos.

Get-ChildItem . -File |
  Where-Object { $_.Length -gt 10MB }
Get-Service |
  Where-Object { $_.Status -in @("Running", "Paused") }
Get-ChildItem . -File |
  Where-Object { $_.Name -match "\.log$" }

Al principio basta con -eq, -ne, -gt, -lt y -like. Cuando se familiarice más, usar -match o -in facilita escribir las condiciones.

33. Pequeñas recetas prácticas

A partir de aquí, se presentan ejemplos en un formato listo para usar directamente en el trabajo.

Ver el número de archivos por extensión

Get-ChildItem C:\Work -File -Recurse |
  Group-Object -Property Extension -NoElement |
  Sort-Object -Property Count -Descending

Se usa cuando quiere hacerse una idea general del contenido de una carpeta.

Ver los 20 archivos más grandes

Get-ChildItem C:\Work -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 20 FullName, @{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }}

Se usa con frecuencia en el estudio del espacio en disco.

Ver los archivos actualizados en las últimas 24 horas

$since = (Get-Date).AddHours(-24)

Get-ChildItem C:\Work -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-Object FullName, Length, LastWriteTime

Se puede usar tras un incidente para ver qué archivos se actualizaron.

Exportar a CSV las líneas de registro que contienen ERROR

Select-String -Path C:\App\Logs\*.log -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8

Facilita compartir el resultado de la investigación.

Ver las 2 líneas anteriores y posteriores a ERROR

Select-String -Path C:\App\Logs\*.log -Pattern "ERROR" -Context 2

Se usa cuando quiere ver el contexto de la causa.

Ver los procesos con mayor uso de memoria

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

Ver los servicios de inicio automático que están detenidos

Get-Service |
  Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
  Select-Object Name, DisplayName, Status, StartType

Exportar a CSV los errores del registro del sistema

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message |
  Export-Csv .\system-errors.csv -NoTypeInformation -Encoding UTF8

Enviar el resultado de un comando al portapapeles

Get-Service |
  Select-Object Name, DisplayName, Status |
  ConvertTo-Csv -NoTypeInformation |
  Set-Clipboard

Resulta útil para pegarlo en un correo o en un chat.

Comparar el listado de archivos antes y después del trabajo

Get-ChildItem C:\Work -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\before.txt -Encoding UTF8

Vuelva a tomarlo después del trabajo.

Get-ChildItem C:\Work -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\after.txt -Encoding UTF8

Compárelos.

Compare-Object (Get-Content .\before.txt) (Get-Content .\after.txt)

Ver el tamaño total de una carpeta en GB

$size = Get-ChildItem C:\Work -File -Recurse |
  Measure-Object -Property Length -Sum

[math]::Round($size.Sum / 1GB, 2)

34. Precauciones al combinarlo con comandos de modificación

Gran parte de lo visto hasta ahora son comandos de lectura, y usar solo estos permite experimentar con relativa tranquilidad. Por otro lado, estos son los comandos de modificación.

Operación Comando
Copiar Copy-Item
Mover Move-Item
Eliminar Remove-Item
Cambiar nombre Rename-Item
Detener proceso Stop-Process
Reiniciar servicio Restart-Service
Configuración persistente de variables de entorno [Environment]::SetEnvironmentVariable()

Los comandos de modificación se usan en el siguiente orden.

1. Ver el objetivo con un comando Get
2. Filtrar con Where-Object
3. Ver el listado de objetivos con Select-Object
4. Contar el número de elementos con Measure-Object
5. Guardarlo con Export-Csv si es necesario
6. Hacer un ensayo con -WhatIf si está disponible
7. Ejecutar

Por ejemplo, caso en que se eliminan archivos .tmp antiguos.

Primero, ver el objetivo.

$limit = (Get-Date).AddDays(-30)

$targets = Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse |
  Where-Object { $_.LastWriteTime -lt $limit }

$targets |
  Select-Object FullName, Length, LastWriteTime

Contar el número de elementos.

$targets | Measure-Object

Guardar en un CSV.

$targets |
  Select-Object FullName, Length, LastWriteTime |
  Export-Csv .\delete-targets.csv -NoTypeInformation -Encoding UTF8

Verificar el plan de eliminación.

$targets | Remove-Item -WhatIf

Si no hay problemas, ejecutar.

$targets | Remove-Item

Con solo respetar este flujo, se reducen considerablemente los incidentes.

35. Cómo recordarlos

Intentar memorizar los comandos uno por uno resulta complicado, así que aprenderlos por objetivo facilita su uso.

Objetivo Comando que recordar
Quiere contar Measure-Object
Quiere sumar Measure-Object -Sum
Quiere verlo por tipo Group-Object
Quiere eliminar duplicados Sort-Object -Unique
Quiere solo el valor necesario Select-Object -ExpandProperty
Quiere ordenar las columnas Select-Object
Quiere verlo de mayor a menor Sort-Object -Descending
Quiere buscar una cadena Select-String
Quiere ver el contexto Select-String -Context
Quiere comparar dos elementos Compare-Object
Quiere dejar evidencia Export-Csv / Start-Transcript
Quiere mostrarlo en pantalla y en archivo Tee-Object
Quiere enviarlo al portapapeles Set-Clipboard
Quiere medir el tiempo Measure-Command
Quiere ver el error en detalle Get-Error

Chuleta de una página

Pensada para imprimir y tener a mano, es una tabla de referencia rápida que incluye la forma exacta de escribir cada comando. Con esto solo puede armar la mayor parte del trabajo diario.

Objetivo Forma lista para usar
Contar el número de archivos Get-ChildItem . -File \| Measure-Object
Ver el tamaño total en GB [math]::Round((Get-ChildItem . -File -Recurse \| Measure-Object -Property Length -Sum).Sum / 1GB, 2)
Número de elementos por extensión Get-ChildItem . -File \| Group-Object -Property Extension -NoElement \| Sort-Object -Property Count -Descending
Los 20 archivos más grandes Get-ChildItem . -File -Recurse \| Sort-Object Length -Descending \| Select-Object -First 20 FullName, Length
Lo actualizado en las últimas 24 horas Get-ChildItem . -File -Recurse \| Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-1) }
Extraer solo el valor Get-Service \| Select-Object -ExpandProperty Name
Eliminar duplicados Get-Content .\list.txt \| Sort-Object -Unique
Buscar ERROR en un registro Select-String -Path .\logs\*.log -Pattern "ERROR"
Ver 2 líneas antes y después de ERROR Select-String -Path .\logs\*.log -Pattern "ERROR" -Context 2
Comparar dos listas Compare-Object -ReferenceObject (Get-Content .\before.txt) -DifferenceObject (Get-Content .\after.txt)
Verificar el valor hash Get-FileHash .\installer.exe -Algorithm SHA256
Enviar el resultado al portapapeles Get-Service \| Select-Object Name, Status \| ConvertTo-Csv -NoTypeInformation \| Set-Clipboard
Mostrar en pantalla y en archivo Get-Process \| Tee-Object -FilePath .\out.txt
Empezar a registrar el trabajo Start-Transcript -Path .\work.log
Filtrar un CSV por condición Import-Csv .\data.csv \| Where-Object { $_.Status -eq "NG" }
Guardar en CSV ... \| Export-Csv .\out.csv -NoTypeInformation -Encoding UTF8
Procesos con más memoria Get-Process \| Sort-Object WorkingSet -Descending \| Select-Object -First 10 Name, Id, WorkingSet
Servicios de inicio automático detenidos Get-Service \| Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" }
Errores del registro de eventos Get-WinEvent -LogName System -MaxEvents 200 \| Where-Object { $_.LevelDisplayName -eq "Error" }
Verificar la conectividad Test-NetConnection -ComputerName example.local -Port 443
Medir el tiempo de ejecución Measure-Command { ... }
Ver en detalle el último error Get-Error

El orden que no debe olvidar

Ver → Contar → Ordenar → Guardar → Ensayar → Ejecutar

Format-Table y Format-List se usan solo al final de este flujo, cuando se trata de ver el resultado en pantalla. Si se intercalan antes de Export-Csv o antes de pasar el resultado al siguiente comando, todo lo que viene después se rompe.

36. Resumen

PowerShell resulta poderoso cuando se sabe escribir scripts. Sin embargo, lo que más se usa en el trabajo diario es, sorprendentemente, la combinación de pequeños comandos.

Contar
Ordenar
Agrupar
Comparar
Buscar
Extraer
Guardar
Enviar al portapapeles
Dejar constancia del trabajo

Con poder hacer solo esto, el trabajo diario se vuelve mucho más sencillo. No hace falta apuntar desde el principio a una automatización compleja. Primero, aprenda a observar la situación con precisión usando comandos de lectura, y solo cuando sea necesario, use comandos de modificación como Copy-Item, Move-Item, Remove-Item o Restart-Service.

La clave para usar PowerShell de forma segura es el siguiente orden.

Ver → Contar → Ordenar → Guardar → Ensayar → Ejecutar

Al interiorizar este patrón, PowerShell deja de ser «algo donde se escriben comandos en una pantalla negra» y se convierte en una herramienta práctica que respalda la investigación, la organización y los informes del día a día.

Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.

Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.

El artículo está directamente relacionado con los siguientes servicios.

Preguntas frecuentes

Preguntas habituales en las consultas sobre el tema del artículo.

¿Cómo puedo averiguar el número de archivos y el tamaño total con PowerShell?
Canalice (pipe) el resultado de Get-ChildItem hacia Measure-Object. El número de elementos se puede consultar en la propiedad Count del resultado, y si desea incluir las subcarpetas, añada -Recurse. El tamaño total se calcula con Measure-Object -Property Length -Sum; como el resultado en bytes es difícil de leer, conviene convertirlo a GB con algo como [math]::Round($size.Sum / 1GB, 2) para que sea más legible. Si añade -Average o -Maximum, también puede obtener el promedio y el valor máximo de una sola vez.
¿En qué se diferencia -ExpandProperty de Select-Object respecto a la forma habitual de usarlo?
Select-Object Name devuelve «una tabla (objeto) con una columna llamada Name», mientras que Select-Object -ExpandProperty Name devuelve «el valor de Name en sí mismo». Cuando quiere exportar a CSV, conviene usar la forma habitual, que conserva el dato como columna; cuando quiere pasar solo el valor a otro comando, a un procesamiento de cadenas o a un archivo de texto, -ExpandProperty resulta más práctico. La elección depende del propósito.
¿Por qué no se debe usar Format-Table antes de Export-Csv?
Porque Format-Table y Format-List son comandos pensados para la visualización en pantalla: convierten la salida en objetos de formato para mostrar, y a partir de ahí ya no es posible exportarla a CSV ni procesarla correctamente. Cuando vaya a exportar a CSV o a procesar el resultado con el siguiente comando, seleccione las columnas con Select-Object antes de pasarlo a Export-Csv. Si recuerda la regla «los comandos Format solo para ver en pantalla; Select-Object cuando vaya a usar el resultado después», no se equivocará.
¿Existe un procedimiento seguro para usar comandos de modificación como Remove-Item?
No los ejecute directamente: primero observe el objetivo con un comando Get, fíltrelo con Where-Object, confirme la lista de elementos con Select-Object, cuente cuántos hay con Measure-Object y, si es necesario, deje constancia con Export-Csv. Después, si el comando admite -WhatIf, haga un ensayo para revisar el plan de eliminación o movimiento y, si no hay problemas, ejecútelo. Con solo respetar este orden se reducen considerablemente los incidentes.

Perfil del autor

Página de presentación del autor del artículo.

Go Komura

Representante de KomuraSoft LLC

Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.

Volver al blog